+ intro NT, binsearch on answer

This commit is contained in:
Benjamin Qi 2020-06-15 22:35:30 -04:00
parent 01fa5daf1e
commit a50e98fc48
5 changed files with 207 additions and 39 deletions

View file

@ -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.
### Tutorial
<!-- END DESCRIPTION -->
- Intro to USACO 12.1
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.
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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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",