+ 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
|
id: binary-search
|
||||||
title: "Binary Search on the Answer"
|
title: "Binary Search on the Answer"
|
||||||
author: Darren Yao
|
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
|
### Problems
|
||||||
|
|
||||||
- USACO
|
- 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
|
- binary search on $K$ and simulate
|
||||||
- [USACO Silver - Convention](http://www.usaco.org/index.php?page=viewproblem2&cpid=858)
|
- [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
|
- 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)
|
- [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.)
|
- [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
|
* straightforward
|
||||||
* [Talent Show](http://www.usaco.org/index.php?page=viewproblem2&cpid=839)
|
* [Talent Show](http://www.usaco.org/index.php?page=viewproblem2&cpid=839)
|
||||||
* binary search + knapsack on weight
|
* 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
|
* CF
|
||||||
* [Round Subset](http://codeforces.com/contest/837/problem/D) [](59)
|
* [Round Subset](http://codeforces.com/contest/837/problem/D) [](59)
|
||||||
* [Fire](http://codeforces.com/contest/864/problem/E) [](59)
|
* [Fire](http://codeforces.com/contest/864/problem/E) [](59)
|
||||||
|
|
|
@ -1,46 +1,98 @@
|
||||||
---
|
---
|
||||||
id: intro-nt
|
id: intro-nt
|
||||||
title: "Introductory Number Theory"
|
title: "Introductory Number Theory"
|
||||||
author: Unknown
|
author: Darren Yao
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="syllabus-only">
|
- Prime Factorization
|
||||||
Description: Todo
|
- GCD & LCM
|
||||||
</div>
|
- Modular Arithmetic
|
||||||
|
|
||||||
<!-- END DESCRIPTION -->
|
<!-- END DESCRIPTION -->
|
||||||
|
|
||||||
See 13 of https://www.overleaf.com/project/5e73f65cde1d010001224d8a
|
## Additional Resources
|
||||||
|
|
||||||
- Prime factorization, GCD, LCM
|
- CSES 21.1, 21.2
|
||||||
- Modular Arithmetic
|
- [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
|
Now, we will discuss how to find the prime factorization of an integer.
|
||||||
- CPH (23, Matrices)
|
|
||||||
- Problems
|
|
||||||
- [Currencies](https://www.hackerrank.com/contests/gs-codesprint/challenges/currencies) [](107)
|
|
||||||
|
|
||||||
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
|
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:
|
||||||
* Tutorial
|
|
||||||
* CPH (21, NT)
|
|
||||||
|
|
||||||
### 5
|
$$\gcd(a, b) = \begin{cases}
|
||||||
|
a & b = 0 \\
|
||||||
|
\gcd(b, a \bmod b) & b \neq 0 \\
|
||||||
|
\end{cases}$$
|
||||||
|
|
||||||
* Modular Arithmetic
|
This algorithm is very easy to implement using a recursive function in Java, as follows:
|
||||||
* Modular Inverse
|
|
||||||
* Chinese Remainder Theorem
|
```java
|
||||||
* Euler's Theorem, Phi Function
|
public int gcd(int a, int b){
|
||||||
* Discrete Logarithm
|
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"
|
"dfs"
|
||||||
],
|
],
|
||||||
"gold": [
|
"gold": [
|
||||||
"intro-nt",
|
|
||||||
"bit",
|
|
||||||
{
|
{
|
||||||
name: "Graphs",
|
name: "Graphs",
|
||||||
items: [
|
items: [
|
||||||
|
@ -67,6 +65,8 @@ const ModuleOrdering = {
|
||||||
"dp-trees"
|
"dp-trees"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
"intro-nt",
|
||||||
|
"bit",
|
||||||
],
|
],
|
||||||
"plat": [
|
"plat": [
|
||||||
"oly",
|
"oly",
|
||||||
|
|
Reference in a new issue