diff --git a/content/4_Gold/BFS.mdx b/content/4_Gold/BFS.mdx index b146dc9..9509f90 100644 --- a/content/4_Gold/BFS.mdx +++ b/content/4_Gold/BFS.mdx @@ -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 = { interactive - + @@ -43,7 +43,70 @@ export const metadata = { ## Implementation - + + + + +From the CSA article: + +```cpp +#include +#include +#include +#include +using namespace std; +const int MAX_N = 100005; + +vector graph[MAX_N]; +int dist[MAX_N]; +bool visited[MAX_N]; + +void bfs(int startNode) { + dist[startNode] = 0; + queue 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; +} +``` + + + + + + + + + + + ## Example: Cow Navigation diff --git a/content/4_Gold/Cyc.mdx b/content/4_Gold/Cyc.mdx index b7ea418..a1b211e 100644 --- a/content/4_Gold/Cyc.mdx +++ b/content/4_Gold/Cyc.mdx @@ -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 --- diff --git a/content/4_Gold/DP.mdx b/content/4_Gold/DP.mdx index 1f5fbe5..e086f76 100644 --- a/content/4_Gold/DP.mdx +++ b/content/4_Gold/DP.mdx @@ -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 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. +Some of the problems in this section don't initially look like Longest Increasing Subsequence, but it ends up being the solution. 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 diff --git a/content/4_Gold/DP_Trees.mdx b/content/4_Gold/DP_Trees.mdx index b0c12ec..305e8ea 100644 --- a/content/4_Gold/DP_Trees.mdx +++ b/content/4_Gold/DP_Trees.mdx @@ -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 = { lol this code format is terrible +## Sample Solution + ## Solving for All Roots diff --git a/content/4_Gold/DSU.mdx b/content/4_Gold/DSU.mdx index 8fbd64e..b74cc10 100644 --- a/content/4_Gold/DSU.mdx +++ b/content/4_Gold/DSU.mdx @@ -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 = { both optimizations, diagrams + both optimizations, no diagrams small to large, diagrams path compression, diagrams - both optimizations, no diagrams diagrams @@ -46,7 +46,32 @@ Note: You may prefer to use this in place of DFS for computing connected compone ## Implementations - +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. + + + + + + + +```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; + } +}; +``` + + + + ## Problems diff --git a/content/4_Gold/Faster_Hash.mdx b/content/4_Gold/Faster_Hash.mdx index 468ebc8..dc99137 100644 --- a/content/4_Gold/Faster_Hash.mdx +++ b/content/4_Gold/Faster_Hash.mdx @@ -5,7 +5,7 @@ author: Benjamin Qi description: "Introduces gp_hash_table." frequency: 1 prerequisites: - - Bronze - Unordered Maps & Sets + - unordered --- import { Problem } from "../models"; diff --git a/content/4_Gold/Intro_NT.mdx b/content/4_Gold/Intro_NT.mdx index bde4901..e4926b3 100644 --- a/content/4_Gold/Intro_NT.mdx +++ b/content/4_Gold/Intro_NT.mdx @@ -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 = { module is based off this + practice problems, set focus to number theory! + good book :D primes and factors, modular arithmetic same as below lots of advanced stuff you don't need to know at this level @@ -52,6 +55,12 @@ Now, we will discuss how to find the prime factorization of an integer. ![Pseudocode](factoralgorithm1.png) + + +replace with code in all langs? + + + 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); } ``` + + +```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)`. + + + -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. + + + +proof? + + + +## 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. $$ + + +Dividing by $\gcd(a,b)$ first might prevent integer overflow. + + + 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: + + + + +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. + + + **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) { -## Modular Inverse (Prime Moduli) +## Modular Inverse + +We'll only consider **prime** moduli here. Division can be performed using modular inverses. - Various ways to take modular inverse + Various ways to take modular inverse ### With Exponentiation @@ -177,7 +221,7 @@ Also, one must always ensure that they do not attempt to divide by 0. Be aware t -See [this module](../adv/extend-euclid). +See the module in the [Advanced](../adv/extend-euclid) section. diff --git a/content/4_Gold/MST.mdx b/content/4_Gold/MST.mdx index c5d1917..e5f025a 100644 --- a/content/4_Gold/MST.mdx +++ b/content/4_Gold/MST.mdx @@ -27,8 +27,6 @@ export const metadata = { } }; -## Sample - ## Resources @@ -41,6 +39,13 @@ export const metadata = { +## Implementation + +### Kruskal's + +### Prim's + + ## USACO Problems diff --git a/content/4_Gold/PURS.mdx b/content/4_Gold/PURS.mdx index f78d80b..48005c3 100644 --- a/content/4_Gold/PURS.mdx +++ b/content/4_Gold/PURS.mdx @@ -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 + + + + based off above -(implementation) + + + - ## Finding $k$-th Element diff --git a/content/4_Gold/SP.mdx b/content/4_Gold/SP.mdx index 4ac3c3a..e9a299b 100644 --- a/content/4_Gold/SP.mdx +++ b/content/4_Gold/SP.mdx @@ -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 --- diff --git a/content/4_Gold/SRQ.mdx b/content/4_Gold/SRQ.mdx index a9071bf..ee333f9 100644 --- a/content/4_Gold/SRQ.mdx +++ b/content/4_Gold/SRQ.mdx @@ -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 = { diff --git a/content/4_Gold/Springboards.mdx b/content/4_Gold/Springboards.mdx index 570164f..dabff80 100644 --- a/content/4_Gold/Springboards.mdx +++ b/content/4_Gold/Springboards.mdx @@ -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 --- diff --git a/content/4_Gold/String_Hashing.mdx b/content/4_Gold/String_Hashing.mdx index a4d4e74..839d36b 100644 --- a/content/4_Gold/String_Hashing.mdx +++ b/content/4_Gold/String_Hashing.mdx @@ -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"; diff --git a/src/components/markdown/ResourcesList.tsx b/src/components/markdown/ResourcesList.tsx index bfa7609..93d264c 100644 --- a/src/components/markdown/ResourcesList.tsx +++ b/src/components/markdown/ResourcesList.tsx @@ -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.',