+ intro NT, binsearch on answer
This commit is contained in:
parent
01fa5daf1e
commit
a50e98fc48
5 changed files with 207 additions and 39 deletions
|
@ -2,20 +2,137 @@
|
|||
id: binary-search
|
||||
title: "Binary Search on the Answer"
|
||||
author: Darren Yao
|
||||
-
|
||||
- Silver - Introduction to Sorting
|
||||
---
|
||||
|
||||
## Binary Searching on the Answer
|
||||
You should already be familiar with the concept of **binary searching** for a number in a sorted array. However, binary search can be extended to binary searching on the answer itself.
|
||||
|
||||
Oftentimes used when you need to find the minimum or maximum of some quantity such that it satisfies some property.
|
||||
<!-- END DESCRIPTION -->
|
||||
|
||||
### Tutorial
|
||||
When we binary search on the answer, we start with a search space of size $N$ which we know the answer lies in. Then, each iteration of the binary search cuts the search space in half, so the algorithm tests $O(\log N)$ values. This is efficient and much better than testing each possible value in the search space.
|
||||
|
||||
- Intro to USACO 12.1
|
||||
Let's say we have a function `check(x)` that returns true if the answer of $x$ is possible, and false otherwise. Usually, in such problems, we'll want to find the maximum or minimum value of $x$ such that `check(x)` is true. Similarly to how binary search on an array only works on a sorted array, binary search on the answer only works if the answer function is [monotonic](https://en.wikipedia.org/wiki/Monotonic_function), meaning that it is always non-decreasing or always non-increasing.
|
||||
|
||||
In particular, if we want to find the maximum `x` such that `check(x)` is true, then we can binary search if `check(x)` satisfies both of the following conditions:
|
||||
|
||||
- If `check(x)` is `true`, then `check(y)` is true for all $y \leq x$.
|
||||
- If `check(x)` is `false`, then `check(y)` is false for all $y \geq x$.
|
||||
|
||||
In other words, we want to reduce the search space to something of the following form, using a check function as we described above.
|
||||
|
||||
<center>true true true true true false false false false</center>
|
||||
|
||||
We want to find the point at which `true` becomes `false`.
|
||||
|
||||
Below, we present two algorithms for binary search. The first implementation may be more intuitive, because it's closer to the binary search most students learned, while the second implementation is shorter.
|
||||
|
||||
(pseudocode)
|
||||
|
||||
If instead we're looking for the minimum `x` that satisfies some condition, then we can binary search if `check(x)` satisfies both of the following conditions:
|
||||
|
||||
- If `check(x)` is true, then `check(y)` is true for all $y \geq x$.
|
||||
- If `check(x)` is false, then `check(y)` is false for all $y \leq x$.
|
||||
|
||||
The binary search function for this is very similar. Find the maximum value of $x$ such that `check(x)` is false with the algorithm above, and return $x+1$.
|
||||
|
||||
## Example: [CF 577 Div. 2 C](https://codeforces.com/contest/1201/problem/C)
|
||||
|
||||
Given an array `arr` of $n$ integers, where $n$ is odd, we can perform the following operation on it $k$ times: take any element of the array and increase it by $1$. We want to make the median of the array as large as possible, after $k$ operations.
|
||||
|
||||
Constraints: $1 \leq n \leq 2 \cdot 10^5, 1 \leq k \leq 10^9$ and $n$ is odd.
|
||||
|
||||
The solution is as follows: we first sort the array in ascending order. Then, we binary search for the maximum possible median. We know that the number of operations required to raise the median to $x$ increases monotonically as $x$ increases, so we can use binary search. For a given median value $x$, the number of operations required to raise the median to $x$ is
|
||||
|
||||
$$\sum_{i=(n+1)/2}^{n} \max(0, x - \text{arr[i]}})$$
|
||||
|
||||
If this value is less than or equal to $k$, then $x$ can be the median, so our check function returns true. Otherwise, $x$ cannot be the median, so our check function returns false.
|
||||
|
||||
The solution codes use the second implementation of binary search.
|
||||
|
||||
Java:
|
||||
```java
|
||||
static int n;
|
||||
static long k;
|
||||
static long[] arr;
|
||||
public static void main(String[] args) {
|
||||
|
||||
n = r.nextInt(); k = r.nextLong();
|
||||
arr = new long[n];
|
||||
for(int i = 0; i < n; i++){
|
||||
arr[i] = r.nextLong();
|
||||
}
|
||||
Arrays.sort(arr);
|
||||
|
||||
pw.println(search());
|
||||
pw.close();
|
||||
}
|
||||
|
||||
// binary searches for the correct answer
|
||||
static long search(){
|
||||
long pos = 0; long max = (long)2E9;
|
||||
for(long a = max; a >= 1; a /= 2){
|
||||
while(check(pos+a)) pos += a;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
// checks whether the number of given operations is sufficient
|
||||
// to raise the median of the array to x
|
||||
static boolean check(long x){
|
||||
long operationsNeeded = 0;
|
||||
for(int i = (n-1)/2; i < n; i++){
|
||||
operationsNeeded += Math.max(0, x-arr[i]);
|
||||
}
|
||||
if(operationsNeeded <= k){ return true; }
|
||||
else{ return false; }
|
||||
}
|
||||
```
|
||||
|
||||
C++:
|
||||
|
||||
```cpp
|
||||
int n;
|
||||
long long k;
|
||||
vector<long long> v;
|
||||
|
||||
// checks whether the number of given operations is sufficient
|
||||
// to raise the median of the array to x
|
||||
bool check(long long x){
|
||||
long long operationsNeeded = 0;
|
||||
for(int i = (n-1)/2; i < n; i++){
|
||||
operationsNeeded += max(0, x-v[i]);
|
||||
}
|
||||
if(operationsNeeded <= k) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
// binary searches for the correct answer
|
||||
long long search(){
|
||||
long long pos = 0; long long max = 2E9;
|
||||
for(long long a = max; a >= 1; a /= 2){
|
||||
while(check(pos+a)) pos += a;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
int main() {
|
||||
cin >> n >> k;
|
||||
for(int i = 0; i < n; i++){
|
||||
int t;
|
||||
cin >> t;
|
||||
v.push_back(t);
|
||||
}
|
||||
sort(v.begin(), v.end());
|
||||
|
||||
cout << search() << '\n';
|
||||
}
|
||||
```
|
||||
|
||||
### Problems
|
||||
|
||||
- USACO
|
||||
- [USACO Silver - Cow Dance](http://www.usaco.org/index.php?page=viewproblem2&cpid=690)
|
||||
- [USACO Silver - Cow Dance Show](http://www.usaco.org/index.php?page=viewproblem2&cpid=690)
|
||||
- binary search on $K$ and simulate
|
||||
- [USACO Silver - Convention](http://www.usaco.org/index.php?page=viewproblem2&cpid=858)
|
||||
- determine whether $M$ buses suffice if every cow waits at most $T$ minutes
|
||||
|
|
|
@ -89,3 +89,7 @@ Which is what we were looking for!
|
|||
|
||||
- [AtCoder Multiple of 2019](https://atcoder.jp/contests/abc164/tasks/abc164_d)
|
||||
- [Google Kick Start Candies](https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ff43/0000000000337b4d) (**only** Test Set 1.)
|
||||
|
||||
## Additional Problems
|
||||
|
||||
- [CF Edu Round 60 C: Magic Ship](https://codeforces.com/problemset/problem/1117/C)
|
|
@ -79,11 +79,6 @@ The following USACO problems don't fall into any of the categories below. Arrang
|
|||
* straightforward
|
||||
* [Talent Show](http://www.usaco.org/index.php?page=viewproblem2&cpid=839)
|
||||
* binary search + knapsack on weight
|
||||
* [Cow Poetry](http://usaco.org/index.php?page=viewproblem2&cpid=897)
|
||||
* First consider the case where there are only two lines with the same class.
|
||||
* Requires fast modular exponentiation for full credit.
|
||||
* [Exercise](http://www.usaco.org/index.php?page=viewproblem2&cpid=1043)
|
||||
* With a bit of number theory
|
||||
* CF
|
||||
* [Round Subset](http://codeforces.com/contest/837/problem/D) [](59)
|
||||
* [Fire](http://codeforces.com/contest/864/problem/E) [](59)
|
||||
|
|
|
@ -1,46 +1,98 @@
|
|||
---
|
||||
id: intro-nt
|
||||
title: "Introductory Number Theory"
|
||||
author: Unknown
|
||||
author: Darren Yao
|
||||
---
|
||||
|
||||
<div class="syllabus-only">
|
||||
Description: Todo
|
||||
</div>
|
||||
- Prime Factorization
|
||||
- GCD & LCM
|
||||
- Modular Arithmetic
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
||||
See 13 of https://www.overleaf.com/project/5e73f65cde1d010001224d8a
|
||||
## Additional Resources
|
||||
|
||||
- Prime factorization, GCD, LCM
|
||||
- Modular Arithmetic
|
||||
- CSES 21.1, 21.2
|
||||
- [CF CodeNCode](https://codeforces.com/blog/entry/77137)
|
||||
|
||||
Also see here: https://codeforces.com/blog/entry/77137
|
||||
## Prime Factorization
|
||||
|
||||
# Binary Exponentiation
|
||||
A number $a$ is called a **divisor** or a **factor** of a number $b$ if $b$ is divisible by $a$, which means that there exists some integer $k$ such that $b = ka$. Conventionally, $1$ and $n$ are considered divisors of $n$. A number $n > 1$ is **prime** if its only divisors are $1$ and $n$. Numbers greater than \(1\) that are not prime are **composite**.
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
Every number has a unique **prime factorization**: a way of decomposing it into a product of primes, as follows:
|
||||
\[ n = {p_1}^{a_1} {p_2}^{a_2} \cdots {p_k}^{a_k} \]
|
||||
where the $p_i$ are distinct primes and the $a_i$ are positive integers.
|
||||
|
||||
- Tutorial
|
||||
- CPH (23, Matrices)
|
||||
- Problems
|
||||
- [Currencies](https://www.hackerrank.com/contests/gs-codesprint/challenges/currencies) [](107)
|
||||
Now, we will discuss how to find the prime factorization of an integer.
|
||||
|
||||
COWBASIC
|
||||
(pseudocode)
|
||||
|
||||
(old)
|
||||
This algorithm runs in $O(\sqrt{n})$ time, because the for loop checks divisibility for at most $\sqrt{n}$ values. Even though there is a while loop inside the for loop, dividing $n$ by $i$ quickly reduces the value of $n$, which means that the outer for loop runs less iterations, which actually speeds up the code.
|
||||
|
||||
Let's look at an example of how this algorithm works, for $n = 252$.
|
||||
|
||||
(table)
|
||||
|
||||
At this point, the for loop terminates, because $i$ is already 3 which is greater than $\lfloor \sqrt{7} \rfloor$. In the last step, we add $7$ to the list of factors $v$, because it otherwise won't be added, for a final prime factorization of $\{2, 2, 3, 3, 7\}$.
|
||||
|
||||
|
||||
### 4
|
||||
## GCD & LCM
|
||||
|
||||
* Eratosthenes' Sieve
|
||||
* Tutorial
|
||||
* CPH (21, NT)
|
||||
The **greatest common divisor (GCD)** of two integers $a$ and $b$ is the largest integer that is a factor of both $a$ and $b$. In order to find the GCD of two numbers, we use the Euclidean Algorithm, which is as follows:
|
||||
|
||||
### 5
|
||||
$$\gcd(a, b) = \begin{cases}
|
||||
a & b = 0 \\
|
||||
\gcd(b, a \bmod b) & b \neq 0 \\
|
||||
\end{cases}$$
|
||||
|
||||
* Modular Arithmetic
|
||||
* Modular Inverse
|
||||
* Chinese Remainder Theorem
|
||||
* Euler's Theorem, Phi Function
|
||||
* Discrete Logarithm
|
||||
This algorithm is very easy to implement using a recursive function in Java, as follows:
|
||||
|
||||
```java
|
||||
public int gcd(int a, int b){
|
||||
if(b == 0) return a;
|
||||
return gcd(b, a % b);
|
||||
}
|
||||
```
|
||||
|
||||
For C++, use the built-in `__gcd(a,b)`. Finding the GCD of two numbers can be done in $O(\log n)$ time, where $n = \min(a, b)$.
|
||||
|
||||
The **least common multiple (LCM)** of two integers $a$ and $b$ is the smallest integer divisible by both $a$ and $b$.
|
||||
|
||||
The LCM can easily be calculated from the following property with the GCD:
|
||||
|
||||
$$\operatorname{lcm}(a, b) = \frac{a \cdot b}{\gcd(a, b)}$$
|
||||
|
||||
If we want to take the GCD or LCM of more than two elements, we can do so two at a time, in any order. For example,
|
||||
|
||||
$$\gcd(a_1, a_2, a_3, a_4) = \gcd(a_1, \gcd(a_2, \gcd(a_3, a_4)))$$
|
||||
|
||||
## Modular Arithmetic
|
||||
|
||||
In **modular arithmetic**, instead of working with integers themselves, we work with their remainders when divided by $m$. We call this taking modulo $m$. For example, if we take $m = 23$, then instead of working with $x = 247$, we use $x \bmod 23 = 17$. Usually, $m$ will be a large prime, given in the problem; the two most common values are $10^9 + 7$, and $998\,244\,353$. Modular arithmetic is used to avoid dealing with numbers that overflow built-in data types, because we can take remainders, according to the following formulas:
|
||||
|
||||
$$\begin{gather*}
|
||||
(a+b) \bmod m = (a \bmod m + b \bmod m) \bmod m \\
|
||||
(a-b) \bmod m = (a \bmod m - b \bmod m) \bmod m \\
|
||||
(a \cdot b) \pmod{m} = ((a \bmod m) \cdot (b \bmod m)) \bmod m \\
|
||||
a^b \bmod {m} = (a \bmod m)^b \bmod m
|
||||
\end{gather*}$$
|
||||
|
||||
### Modular Exponentiation
|
||||
|
||||
?
|
||||
|
||||
### Modular Inverse
|
||||
|
||||
Under a prime moduli, division exists.
|
||||
|
||||
## Problems
|
||||
|
||||
- USACO
|
||||
- Both are also Knapsack DP problems.
|
||||
- [Cow Poetry](http://usaco.org/index.php?page=viewproblem2&cpid=897)
|
||||
- First consider the case where there are only two lines with the same class.
|
||||
- Requires fast modular exponentiation for full credit.
|
||||
- [Exercise](http://www.usaco.org/index.php?page=viewproblem2&cpid=1043)
|
||||
- Prime factorization
|
||||
- Other
|
||||
- [CF VK Cup 2012 Wildcard Round 1 C](https://codeforces.com/problemset/problem/162/C)
|
|
@ -49,8 +49,6 @@ const ModuleOrdering = {
|
|||
"dfs"
|
||||
],
|
||||
"gold": [
|
||||
"intro-nt",
|
||||
"bit",
|
||||
{
|
||||
name: "Graphs",
|
||||
items: [
|
||||
|
@ -67,6 +65,8 @@ const ModuleOrdering = {
|
|||
"dp-trees"
|
||||
]
|
||||
}
|
||||
"intro-nt",
|
||||
"bit",
|
||||
],
|
||||
"plat": [
|
||||
"oly",
|
||||
|
|
Reference in a new issue