This commit is contained in:
Benjamin Qi 2020-07-18 20:22:28 -04:00
parent 7d4f88925b
commit 088d0260e1
14 changed files with 181 additions and 32 deletions

View file

@ -3,7 +3,7 @@ id: bfs
title: "Breadth First Search (BFS)"
author: Benjamin Qi, Michael Cao
prerequisites:
- Silver - Depth First Search
- dfs
description: "Traversing a graph in a way such that vertices closer to the starting vertex are processed first."
frequency: 2
---
@ -33,7 +33,7 @@ export const metadata = {
<Resources>
<Resource source="CSA" title="Breadth First Search" url="breadth_first_search" starred>interactive</Resource>
<Resource source="CPH" title="12.2 - Breadth-First Search" starred></Resource>
<Resource source="CPH" title="12.2 - Breadth-First Search"></Resource>
<Resource source="PAPS" title="12.1 - Breadth-First Search"></Resource>
<Resource source="KA" title="Breadth First Search and Its Uses" url="https://www.khanacademy.org/computing/computer-science/algorithms/breadth-first-search/a/breadth-first-search-and-its-uses"></Resource>
<Resource source="cp-algo" title="Breadth First Search" url="graph/breadth-first-search.html"></Resource>
@ -43,7 +43,70 @@ export const metadata = {
## Implementation
<IncompleteSection />
<LanguageSection>
<CPPSection>
From the CSA article:
```cpp
#include <algorithm>
#include <fstream>
#include <iostream>
#include <queue>
using namespace std;
const int MAX_N = 100005;
vector<int> graph[MAX_N];
int dist[MAX_N];
bool visited[MAX_N];
void bfs(int startNode) {
dist[startNode] = 0;
queue<int> bfsQueue;
bfsQueue.push(startNode);
visited[startNode] = true;
while (!bfsQueue.empty()) {
int currentNode = bfsQueue.front();
bfsQueue.pop();
for (auto neighbour: graph[currentNode]) {
if (!visited[neighbour]) {
visited[neighbour] = true;
dist[neighbour] = dist[currentNode] + 1;
bfsQueue.push(neighbour);
}
}
}
}
int main() {
int N, M, v, x, y;
cin >> N >> M >> v;
for (int i = 1; i <= M; i += 1) {
cin >> x >> y;
graph[x].push_back(y);
}
for (int i = 1; i <= N; i += 1) {
dist[i] = -1;
}
bfs(v);
for (int i = 1; i <= N; i += 1) {
cout << dist[i] << " ";
}
return 0;
}
```
</CPPSection>
<JavaSection>
</JavaSection>
</LanguageSection>
## Example: Cow Navigation

View file

@ -3,7 +3,7 @@ id: cyc
title: Cycle Detection
author: Siyong Huang
prerequisites:
- Gold - Topological Sort
- toposort
description: "A simple cycle is a non-empty path of distinct edges that start and end at the same vertex such that no vertex appears more than once. Describes how to detect cycles in both directed and undirected graphs."
frequency: 0
---

View file

@ -2,7 +2,8 @@
id: intro-dp
title: "Introduction to Dynamic Programming"
author: Michael Cao
prerequisites:
prerequisites:
- complete-search
- prefix-sums
description: "Speeding up naive recursive solutions with memoization."
frequency: 4
@ -44,7 +45,8 @@ export const metadata = {
new Problem("Old Gold", "Palindromic Paths", "553", "Hard", false, ["DP"], "start from the middle, dp[row i][row j][length] = number of strings of length 2 * length + 1 with ends at row i and j"),
],
lis: [
new Problem("LC", "Longest Increasing Subsequence", "https://leetcode.com/problems/longest-increasing-subsequence/", "Easy", true, ["DP"], "dp[i] = LIS up to i, use binary search to decrease runtime from quadratic"),
new Problem("LC", "Longest Increasing Subsequence", "https://leetcode.com/problems/longest-increasing-subsequence/", "Very Easy", true, ["DP"], "dp[i] = LIS up to i, use binary search to decrease runtime from quadratic"),
new Problem("Kattis", "Longest Increasing Subsequence", "longincsubseq", "Easy", true, [], ""),
new Problem("Old Gold", "Cowjog", "496", "Easy", false, ["DP"], "direct application of longest increasing subsequence"),
new Problem("Plat", "Sort It Out", "865", "Very Hard", false, ["DP"], "component of kth largest LIS, read editorial for more details"),
],
@ -97,7 +99,7 @@ Interesting applications of "number of paths on a grid," some of which don't dir
## Longest Increasing Subsequence
The first problem requires a quadratic time complexity solution to Longset Increasing subsequence, but you should optimize it to $O(N \log N)$. Some of the problems in this section don't initially look like Longest Increasing Subsequence, but it ends up being the solution <Asterick>This can happen a lot, which is why it's a good idea to not focus on one topic unless you have a full solution</Asterick>.
Some of the problems in this section don't initially look like Longest Increasing Subsequence, but it ends up being the solution. <Asterisk>This can happen a lot, which is why it's a good idea to not focus on one topic unless you have a full solution</Asterisk>
<Problems problems={metadata.problems.lis} />

View file

@ -3,8 +3,8 @@ id: dp-trees
title: "Dynamic Programming on Trees"
author: Michael Cao
prerequisites:
- Silver - Depth First Search
- Gold - Introduction to Dynamic Programming
- dfs
- intro-dp
description: "Using subtrees as subproblems."
frequency: 1
---
@ -39,6 +39,8 @@ export const metadata = {
<Resource source="Philippines" title="DP on Trees and DAGs" url="https://noi.ph/training/weekly/week5.pdf">lol this code format is terrible </Resource>
</Resources>
## Sample Solution
## Solving for All Roots
<Problems problems={metadata.problems.allRoots} />

View file

@ -3,7 +3,7 @@ id: dsu
title: "Disjoint Set Union"
author: Benjamin Qi, Michael Cao
prerequisites:
- Silver - Depth First Search
- dfs
description: "The Disjoint Set Union (DSU) data structure allows you to add edges to an initially empty graph and test whether two vertices of the graph are connected."
frequency: 3
---
@ -28,9 +28,9 @@ export const metadata = {
<Resources>
<Resource source="CSA" title="Disjoint Data Sets" url="disjoint_data_sets" starred>both optimizations, diagrams</Resource>
<Resource source="PAPS" title="11.1 - Disjoint Sets" starred>both optimizations, no diagrams</Resource>
<Resource source="CPH" title="15.2 - Union-Find">small to large, diagrams</Resource>
<Resource source="IUSACO" title="10.6 - Disjoint-Set Data Structure">path compression, diagrams</Resource>
<Resource source="PAPS" title="11.1 - Disjoint Sets">both optimizations, no diagrams</Resource>
<Resource source="TC" title="Disjoint Set Data Structures" url="disjoint-set-data-structures">diagrams</Resource>
<Resource source="CPC" title="3 - Data Structures" url="03_data_structures"></Resource>
</Resources>
@ -46,7 +46,32 @@ Note: You may prefer to use this in place of DFS for computing connected compone
## Implementations
<IncompleteSection />
Check PAPS for the explanation. `e[x]` contains the negation of the size of $x$'s component if $x$ is the representative of its component, and the parent of $x$ otherwise.
<LanguageSection>
<CPPSection>
<resource source="Benq (from KACTL)" url="https://github.com/bqi343/USACO/blob/master/Implementations/content/graphs%20(12)/DSU/DSU%20(7.6).h"> </resource>
```cpp
struct DSU {
vi e; void init(int N) { e = vi(N,-1); }
// get representive component, uses path compression
int get(int x) { return e[x] < 0 ? x : e[x] = get(e[x]); }
bool sameSet(int a, int b) { return get(a) == get(b); }
int size(int x) { return -e[get(x)]; }
bool unite(int x, int y) { // union by size
x = get(x), y = get(y); if (x == y) return 0;
if (e[x] > e[y]) swap(x,y);
e[x] += e[y]; e[y] = x; return 1;
}
};
```
</CPPSection>
</LanguageSection>
## Problems

View file

@ -5,7 +5,7 @@ author: Benjamin Qi
description: "Introduces gp_hash_table."
frequency: 1
prerequisites:
- Bronze - Unordered Maps & Sets
- unordered
---
import { Problem } from "../models";

View file

@ -4,6 +4,7 @@ title: "Introductory Number Theory"
author: Darren Yao, Michael Cao
prerequisites:
- intro-dp
- binary representation
description: Introduces divisibility and modular arithmetic.
frequency: 1
---
@ -31,6 +32,8 @@ export const metadata = {
<Resources>
<Resource source="IUSACO" title="13 - Elementary Number Theory">module is based off this</Resource>
<Resource source="AoPS" title="Alcumus" url="https://artofproblemsolving.com/alcumus/problem" starred>practice problems, set focus to number theory!</Resource>
<Resource source="AoPS" title ="Intro to NT" url="https://artofproblemsolving.com/store/item/intro-number-theory?gtmlist=Bookstore_AoPS_Side">good book :D</Resource>
<Resource source="CPH" title="21.1, 21.2 - Number Theory">primes and factors, modular arithmetic</Resource>
<Resource source="PAPS" title="16 - Number Theory">same as below</Resource>
<Resource source="CF" title="CodeNCode - Number Theory Course" url="blog/entry/77137">lots of advanced stuff you don't need to know at this level</Resource>
@ -52,6 +55,12 @@ Now, we will discuss how to find the prime factorization of an integer.
![Pseudocode](factoralgorithm1.png)
<IncompleteSection>
replace with code in all langs?
</IncompleteSection>
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$.
@ -61,9 +70,9 @@ Let's look at an example of how this algorithm works, for $n = 252$.
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\}$.
## GCD & LCM
## GCD
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:
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:
$$
\gcd(a, b) = \begin{cases}
@ -80,25 +89,52 @@ This algorithm is very easy to implement using a recursive function, as follows:
```java
public int gcd(int a, int b){
if(b == 0) return a;
if (b == 0) return a;
return gcd(b, a % b);
}
```
</JavaSection>
<CPPSection>
```cpp
int GCD(int a, int b){
if (b == 0) return a;
return GCD(b, a % b);
}
```
For C++14 and below, use the built-in `__gcd(a,b)`. C++17 has built in `gcd(a,b)`.
</CPPSection>
</LanguageSection>
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)$.
This function runs in $O(\log \max(a,b))$ time.
<IncompleteSection>
proof?
</IncompleteSection>
## LCM
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)}.
\operatorname{lcm}(a, b) = \frac{a \cdot b}{\gcd(a, b)}=\frac{a}{\gcd(a,b)}\cdot b.
$$
<Warning>
Dividing by $\gcd(a,b)$ first might prevent integer overflow.
</Warning>
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,
$$
@ -107,7 +143,11 @@ $$
## 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:
<Resources>
<Resource source="David Altizio" title="Modular Arithmetic" url="https://davidaltizio.web.illinois.edu/ModularArithmetic.pdf" starred> </Resource>
</Resources>
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=119\cdot 2^{23}+1$. 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:
$$
(a+b) \bmod m = (a \bmod m + b \bmod m) \bmod m
@ -127,7 +167,9 @@ $$
## Modular Exponentiation
Under a **prime** modulus, division can be performed using modular inverses.
<Resources>
<Resource source="cp-algo" title="Binary Exponentiation" url="algebra/binary-exp.html"> </Resource>
</Resources>
**Modular Exponentiation** can be used to efficently compute $x ^ n \mod m$. To do this, let's break down $x ^ n$ into binary components. For example, $5 ^ {10}$ = $5 ^ {1010_2}$ = $5 ^ 8 \cdot 5 ^ 4$. Then, if we know $x ^ y$ for all $y$ which are powers of two ($x ^ 1$, $x ^ 2$, $x ^ 4$, $\dots$ , $x ^ {2^{\lfloor{\log_2n} \rfloor}}$, we can compute $x ^ n$ in $\mathcal{O}(\log n)$. Finally, since $x ^ y$ for some $y \neq 1$ equals $2 \cdot x ^ {y - 1}$, and $x$ otherwise, we can compute these sums efficently. To deal with $m$, observe that modulo doesn't affect multiplications, so we can directly implement the above "binary exponentiation" algorithm while adding a line to take results $\pmod m$.
@ -155,10 +197,12 @@ long long binpow(long long x, long long n, long long m) {
</LanguageSection>
## Modular Inverse (Prime Moduli)
## Modular Inverse
We'll only consider **prime** moduli here. Division can be performed using modular inverses.
<Resources>
<Resource source="CP-Algorithms" title="Modular Multiplicative Inverse" url="https://cp-algorithms.com/algebra/module-inverse.html">Various ways to take modular inverse</Resource>
<Resource source="cp-algo" title="Modular Multiplicative Inverse" url="algebra/module-inverse.html">Various ways to take modular inverse</Resource>
</Resources>
### With Exponentiation
@ -177,7 +221,7 @@ Also, one must always ensure that they do not attempt to divide by 0. Be aware t
<Optional>
See [this module](../adv/extend-euclid).
See the module in the [Advanced](../adv/extend-euclid) section.
</Optional>

View file

@ -27,8 +27,6 @@ export const metadata = {
}
};
## Sample
<Problems problems={metadata.problems.standard} />
## Resources
@ -41,6 +39,13 @@ export const metadata = {
<Resource source="cp-algo" title="Kruskal's with DSU" url="graph/mst_kruskal_with_dsu.html"></Resource>
</Resources>
## Implementation
### Kruskal's
### Prim's
## USACO Problems
<Problems problems={metadata.problems.general} />

View file

@ -3,7 +3,7 @@ id: PURS
title: "Point Update Range Sum"
author: Benjamin Qi
prerequisites:
- Silver - Prefix Sums
- prefix-sums
description: "Introducing Segment Trees, Binary Indexed Trees, and Indexed Sets (C++ only)."
frequency: 3
---
@ -55,7 +55,7 @@ Most gold range query problems require you to support following tasks in $O(\log
- Update the element at a single position (point).
- Query the sum of some consecutive subarray.
Both **segment tree*s* and **binary indexed trees** can accomplish this.
Both **segment trees** and **binary indexed trees** can accomplish this.
## Segment Tree
@ -128,14 +128,19 @@ Implementation is shorter than segment tree, but maybe more confusing at first g
### Implementations
<LanguageSection>
<CPPSection>
<Resources>
<Resource source="CF" title="mouse_wireless - Multi-dimensional BITs with Templates" url="https://codeforces.com/blog/entry/64914" starred></Resource>
<Resource source="Benq" title="BIT" url="https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BIT%20(9.2).h">based off above</Resource>
</Resources>
(implementation)
</CPPSection>
</LanguageSection>
<IncompleteSection />
## Finding $k$-th Element

View file

@ -3,7 +3,7 @@ id: sp
title: "Shortest Paths with Non-Negative Edge Weights"
author: Benjamin Qi
prerequisites:
- Gold - Breadth First Search
- bfs
description: "Introduces Dijkstra's Algorithm for a single source shortest path as well as Floyd-Warshall for All-Pairs Shortest Path."
frequency: 3
---

View file

@ -5,6 +5,7 @@ author: Benjamin Qi
description: "Range queries for any associative operation over a static array."
frequency: 1
---
import { Problem } from "../models";
export const metadata = {

View file

@ -3,8 +3,7 @@ id: springboards
title: "Max Suffix Query with Insertions Only"
author: Benjamin Qi
prerequisites:
- Silver - More with Maps & Sets
- Silver - Amortized Analysis
- harder-ordered
description: "A solution to USACO Gold - Springboards."
frequency: 1
---

View file

@ -4,6 +4,8 @@ title: "String Hashing"
author: Benjamin Qi
description: "Quickly test equality of substrings with a small probability of failure."
frequency: 1
prerequisites:
- intro-nt
---
import { Problem } from "../models";

View file

@ -76,6 +76,7 @@ export const sourceTooltip = {
LC: 'LeetCode',
POI: 'Polish Olympiad in Informatics',
SO: 'StackOverflow',
KA: 'KhanAcademy',
'Old Bronze': 'USACO Platinum did not exist prior to 2015-16.',
'Old Silver': 'USACO Platinum did not exist prior to 2015-16.',
'Old Gold': 'USACO Platinum did not exist prior to 2015-16.',