This commit is contained in:
Nathan Wang 2020-07-19 20:13:38 -07:00
commit f48a57122b
54 changed files with 895 additions and 613 deletions

View file

@ -2,10 +2,11 @@
id: code-con
title: Code Conventions
author: Nathan Wang, Benjamin Qi, Michael Cao, Nathan Chen
description: "The conventions that this guide uses"
description: "What the code we provide should look like."
prerequisites:
- expected
- modules
- cpp-tips
---
The code we provide should follow the conventions below. Please note that you do _not_ have to copy our conventions; there is no "right" convention for coding!
@ -97,7 +98,7 @@ The "template" refers to code that is assumed to be in every file.
Templates in C++ can take advantange of more powerful features than the other contest languages, and they can be more customized to each competitor. Don't be afraid to write your own template or don't use one at all! Regardless, The USACO Guide will assume the use of the below template in any C++ Code.
See [C++ Tips & Tricks](./cpp-tips) for explanations of the following code.
<!-- See [C++ Tips & Tricks](./cpp-tips) for explanations of the following code. -->
```cpp
#include <bits/stdc++.h>

View file

@ -19,6 +19,12 @@ You should read *all* the problems first (don't give up on any problems prematur
Problem difficulties can be out of order, so keep that in mind before focusing down 3 hours on problem 1 and not getting anywhere. Do a good amount of thinking on each problem before deciding which ones to focus on and which to put aside.
<Info title="Pro Tip">
Historically, the first platinum problem has never been the hardest (though you shouldn't count on this).
</Info>
### Time allocation
It's the worst feeling in the world to sink a couple hours into a problem before realizing that a different problem would've been easy pickings; we can easily avoid this situation with proper time allocation. You have to use your own judgement in deciding what is likely solvable and what should be quit. Generally, don't spend "too long" on one problem, and stay away from problems that look like they test something you don't know well.

View file

@ -5,16 +5,20 @@ author: Benjamin Qi
description: Contests that I participate in as well as a few tools.
---
See [clist.by](https://clist.by/coder/bqi343/) for an extensive list of contests. Make sure to [upsolve](https://en.wiktionary.org/wiki/upsolve) after the contest ends!
Make sure to [upsolve](https://en.wiktionary.org/wiki/upsolve) after the contest ends!
## Contests that I regularly participate in
<Resources>
<Resource source="CLIST" title="My Profile" url="https://clist.by/coder/bqi343/" starred>extensive list of contests</Resource>
<Resource source="kenkoooo" title="AtCoder Visualizer" url="https://kenkoooo.com/atcoder/#/table/Benq" starred>keep track of which problems you've done</Resource>
</Resources>
- [AtCoder](https://beta.atcoder.jp/contests/archive)
- probably the highest quality, although difficulty isn't *always* reasonable
- Contests
- Beginner / Regular: 4 or 6 problems, ~100 min
- Grand: 6 problems, 110 - 150 min
- [Visualizer](https://kenkoooo.com/atcoder/#/table/Benq)
- [Codeforces](http://codeforces.com/problemset)
- Contests
- Div 1/2/3/(4?): 5-6 problems (with some variations), 2 to 2.5 hrs
@ -29,26 +33,21 @@ See [clist.by](https://clist.by/coder/bqi343/) for an extensive list of contests
## Other Websites
- [Google Kickstart](https://codingcompetitions.withgoogle.com/kickstart)
- Feb - Nov
- [Kattis](https://open.kattis.com/)
- misc ICPC contests
- [HackerEarth](http://hackerearth.com/)
- Monthly "Easy"
- quality is not always good
- [Codechef](http://codechef.com/)
- Lunchtime, Cookoff
- quality is not always good
- [HackerRank](https://www.hackerrank.com/dashboard)
- Apparently there are only "Hack the Interview" contests now.
<Resources>
<Resource title="Kattis" url="https://open.kattis.com/">misc ICPC contests</Resource>
<Resource title="TOKI" url="https://tlx.toki.id/">Indonesian</Resource>
<Resource title="Kickstart" url="https://codingcompetitions.withgoogle.com/kickstart">Feb - Nov</Resource>
<Resource title="HackerEarth" url="http://hackerearth.com/">Monthly "Easy" - quality is not always good</Resource>
<Resource title="CodeChef" url="http://codechef.com/">Monthly Long, Lunchtime, Cookoff - quality is not always good</Resource>
<Resource title="HackerRank" url="https://www.hackerrank.com/dashboard">apparently only "Hack the Interview" contests now</Resource>
<Resource title="CSAcademy" url="https://csacademy.com/contest/archive/">no regular contests anymore, archive is still worth a look</Resource>
</Resources>
[CS Academy](https://csacademy.com/contest/archive/) does not hold regular contests anymore, but it's still worth looking at.
- Contests
<!-- - Contests
- Div 2: 5 problems, 2 hrs
- Open: 7 problems, 2 hrs
- Archive
- short statements, good editorials
- short statements, good editorials -->
## Onsite Finals (Individual)
@ -74,20 +73,25 @@ Only considering contests which allow C++ since the others aren't legit. (add mo
## Codeforces Tools
- [Stopstalk](https://www.stopstalk.com)
- [Code Drills](http://code-drills.com/)
- [CF Visualizer](http://cfviz.netlify.com/compare.html)
- [CF Rating Predictor](https://chrome.google.com/webstore/detail/cf-predictor/ocfloejijfhhkkdmheodbaanephbnfhn)
- [CF Command Line](https://codeforces.com/blog/entry/66552)
- [CF Editor](https://codeforces.com/blog/entry/72952)
<Resources>
<Resource title="CF-Predictor" url="https://chrome.google.com/webstore/detail/cf-predictor/ocfloejijfhhkkdmheodbaanephbnfhn" starred>estimate rating changes!</Resource>
<Resource title="Stopstalk" url="https://www.stopstalk.com">keep track of friends' progress</Resource>
<Resource title="Code Drills" url="https://recommender.codedrills.io/">problem recommender (haven't used personally) </Resource>
<Resource title="CF Visualizer" url="http://cfviz.netlify.com/compare.html">compare users </Resource>
<Resource title="CF Command Line Tool" url="https://codeforces.com/blog/entry/66552">parse problem statements, submit, etc from command line</Resource>
<Resource title="CF Editor" url="https://codeforces.com/blog/entry/72952">text editor using features from above</Resource>
</Resources>
<!-- - [CF Enhancer](https://chrome.google.com/webstore/detail/codeforces-enhancer/ocmandagmgmkcplckgnfgaokpgkfenmp)
- no longer works -->
## Contest Tools
- [2D Geo Visualizer](https://codeforces.com/blog/entry/70330)
- [CSAcademy Graph Editor (+ Geo Visualizer + Diff Tool)](https://csacademy.com/app/graph_editor/)
- [Desmos Grapher](https://www.desmos.com/calculator)
- [Wolfram Alpha](https://www.wolframalpha.com/)
- [OEIS](https://oeis.org/)
<Resources>
<Resource title="Wolfram Alpha" url="https://www.wolframalpha.com/" starred> </Resource>
<Resource title="CSAcademy Graph Editor, Geo Visualizer" url="https://csacademy.com/app/graph_editor/" starred> </Resource>
<Resource title="Desmos Grapher" url="https://www.desmos.com/calculator" starred> </Resource>
<Resource title="Diff Checker" url="https://www.diffchecker.com/"> </Resource>
<Resource title="2D Geo Visualizer (C++)" url="https://codeforces.com/blog/entry/70330"></Resource>
<Resource title="OEIS" url="https://oeis.org/">integer sequences</Resource>
</Resources>

View file

@ -2,7 +2,7 @@
id: debugging
title: Debugging
author: Benjamin Qi, Aaron Chew
description: "Debugging your code is an extremely important skill. Here are some useful debugging-related tips."
description: "Identifying errors within your program and how to avoid them in the first place."
---
## Within Your Program

View file

@ -3,6 +3,8 @@ id: factors-choosing
title: "Factors to Consider When Choosing a Language"
author: Benjamin Qi
description: Reasons why choice of language matters significantly outside of USACO Bronze.
prerequisites:
- choosing-lang
---
## Notes

View file

@ -1,29 +1,33 @@
---
id: lambda
title: Lambda Functions in C++
title: Lambda Expressions
author: Benjamin Qi
description: "?"
description: "Unnamed function objects capable of capturing variables in scope."
---
<LanguageSection>
<CPPSection>
## Introduction
<Resources>
<Resource
source="GFG"
url="lambda-expression-in-c"
title="Lambda Expressions in C++"
>
{' '}
</Resource>
<Resource source="SO" url="https://stackoverflow.com/questions/41121441/type-of-a-lambda-function-using-auto" title="Type of a lambda function, using auto">
</Resource>
<Resource source="CPP" url="https://en.cppreference.com/w/cpp/language/lambda" title="Lambda">reference</Resource>
<Resource source="CPP" url="https://en.cppreference.com/w/cpp/language/lambda" title="Lambda expressions">reference</Resource>
<Resource source="UMich" url="http://umich.edu/~eecs381/handouts/Lambda.pdf" title="Using C++ Lambdas" starred> </Resource>
<Resource source="SO" url="https://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11" title="What is a lambda expression in C++11?"> </Resource>
<Resource source="Microsoft" url="https://docs.microsoft.com/en-us/cpp/cpp/lambda-expressions-in-cpp?view=vs-2019" title="Lambda Expressions in C++"> </Resource>
</Resources>
(describe more)
Anything more beginner-friendly?
oops sort of confusing
<IncompleteSection />
<Resources title="FAQ">
<Resource source="SO" url="https://stackoverflow.com/questions/41121441/type-of-a-lambda-function-using-auto" title="Type of a lambda function using auto?">
</Resource>
<Resource source="SO" url="https://stackoverflow.com/questions/11323811/what-is-meant-by-retain-state-in-c" title="What is meant by 'retain state' in c++?"> </Resource>
</Resources>
## Recursive Lambdas
@ -32,41 +36,49 @@ oops sort of confusing
<Resource source="RIP Tutorial" url="https://riptutorial.com/cplusplus/example/8508/recursive-lambdas" title="Recursive Lambdas"> </Resource>
</Resources>
We can do stuff like the following in C++14:
If we add the following from the link above in C++14:
```cpp
namespace std {
template<class Fun>
class y_combinator_result {
Fun fun_;
Fun fun_;
public:
template<class T>
explicit y_combinator_result(T &&fun): fun_(std::forward<T>(fun)) {}
template<class T>
explicit y_combinator_result(T &&fun): fun_(std::forward<T>(fun)) {}
template<class ...Args>
decltype(auto) operator()(Args &&...args) {
return fun_(std::ref(*this), std::forward<Args>(args)...);
}
template<class ...Args>
decltype(auto) operator()(Args &&...args) {
return fun_(std::ref(*this), std::forward<Args>(args)...);
}
};
template<class Fun>
decltype(auto) y_combinator(Fun &&fun) {
return y_combinator_result<std::decay_t<Fun>>(std::forward<Fun>(fun));
return y_combinator_result<std::decay_t<Fun>>(std::forward<Fun>(fun));
}
} // namespace std
```
Then we can have code like the following!
```cpp
int main() {
cout << y_combinator([](auto gcd, int a, int b) -> int {
return b == 0 ? a : gcd(b, a % b);
})(20,30) << "\n"; // outputs 10
cout << y_combinator([](auto gcd, int a, int b) -> int {
return b == 0 ? a : gcd(b, a % b);
})(20,30) << "\n"; // outputs 10
}
```
Looks like [ecnerwal](https://codeforces.com/contest/1375/submission/86008510) uses these a lot ...
</CPPSection>
</LanguageSection>
<!--
import InputOutput from "../../additionalcontent/Input_Output.mdx";
import DebuggingCpp from "../../additionalContent/Debugging_Cpp.mdx";

View file

@ -98,7 +98,7 @@ A warning block like this will contain common errors that you should avoid.
<IncompleteSection>
These will appear frequently within incomplete modules. Contact us if you want these to be completed (or would like to complete them yourself)!
These will appear frequently.
</IncompleteSection>

View file

@ -282,11 +282,11 @@ java
If you get the below result, you may have to add the JDK to your [PATH](https://docs.oracle.com/en/java/javase/14/install/installation-jdk-microsoft-windows-platforms.html#GUID-A7E27B90-A28D-4237-9383-A58B416071CA) variable.
```
'java' is not recognized as an internal or external comman,
'java' is not recognized as an internal or external command,
operable program or batch file
```
If you get a list of command arguments for the `java` command, you're probably good to go.
Otherwise, you're probably good to go.
<IncompleteSection>

View file

@ -2,7 +2,7 @@
id: cpp-tips
title: C++ Tips & Tricks
author: Benjamin Qi
description: "?"
description: "Things you should know about my template."
---
## `#include <bits/stdc++.h>`

View file

@ -1,8 +1,8 @@
---
id: usaco-camp
title: Making USACO Camp
title: USACO Camp
author: Benjamin Qi
description: ""
description: "Relevant Quora links (and more) regarding camp qualification."
---
<Resources>

View file

@ -2,7 +2,7 @@
id: complete-search
title: "Complete Search"
author: Darren Yao
description: "Solving bronze problems with complete search, or checking all possible cases in the solution space."
description: "Solving bronze problems by checking all possible cases in the solution space."
frequency: 4
---

View file

@ -2,7 +2,7 @@
id: gen-perm
title: "Generating Permutations"
author: Darren Yao, Sam Zhang
description: "Methods to generate all permutations of an array in C++ and Java (and Python?), a common technique associated with complete search."
description: "Methods to generate all permutations of an array, a common technique associated with complete search."
frequency: 4
prerequisites:
- complete-search

View file

@ -2,7 +2,7 @@
id: intro-ds
title: Introduction to Data Structures
author: Darren Yao, Benjamin Qi
description: "Basic data structures in multiple languages such as dynamic arrays."
description: "Basic data structures in multiple languages, dynamic arrays and sorting."
frequency: 4
---
@ -10,15 +10,19 @@ import { Problem } from "../models";
export const problems = {
bubble: [
new Problem("HR", "Bubble Sort", "https://www.hackerrank.com/challenges/ctci-bubble-sort/problem", "Easy", false, [], "O(N^2)"),
new Problem("HR", "Bubble Sort", "https://www.hackerrank.com/challenges/ctci-bubble-sort/problem", "Very Easy", false, [], ""),
],
easy: [
new Problem("CF", "Kayaking", "contest/863/problem/B", "Easy", false, [], ""),
new Problem("CSES", "Distinct Numbers", "1621", "Easy"),
new Problem("CSES", "Stick Lengths", "1074", "Normal", false, [], "Spoiler: Optimal length is median"),
new Problem("Silver", "Teleportation", "812", "Very Hard", false, [], ""),
],
};
<!--
new Problem("Silver", "Teleportation", "812", "Very Hard", false, [], ""),
-->
<Resources>
<Resource source="IUSACO" title="4.1 - Dynamic Arrays">module is based off this</Resource>
<Resource source="CPH" title="4.1 - Dynamic Arrays" starred>vectors, strings</Resource>
@ -279,18 +283,27 @@ for(auto element : v) {
<Problems problems={problems.bubble} />
**Sorting** refers to arranging items in some particular order. You do not need to know how to sort an array in $O(N\log N)$ time for Bronze, but you should be aware of how to use built-in methods to sort a (possibly dynamic) array.
**Sorting** refers to arranging items in some particular order.
<Resources>
<Resource source="CPH" title="3.1 - Sorting Theory"> </Resource>
</Resources>
<!-- No bronze problem should require you to sort an array in $O(N\log N)$ time for Bronze, -->
You should know how to use built-in methods to sort a (possibly dynamic) array.
<LanguageSection>
<CPPSection>
In order to sort a dynamic array, use `sort(v.begin(), v.end())` (or `sort(begin(v),end(v))`), whereas static arrays require `sort(arr, arr + N)` where $N$ is the number of elements to be sorted. The default sort function sorts the array in ascending order.
<Resources>
<Resource source="CPH" title="3.2 - Sorting in C++" starred>can stop before comparison operators, which are covered in silver</Resource>
<Resource source="CPP" title="std::sort" url="https://en.cppreference.com/w/cpp/algorithm/sort">reference</Resource>
<Resource source="CF" title="C++ Tricks" url="blog/entry/74684">first two related to sorting</Resource>
</Resources>
- [std::sort](https://en.cppreference.com/w/cpp/algorithm/sort)
- [std::stable\_sort](http://www.cplusplus.com/reference/algorithm/stable_sort/)
- [Golovanov399 - C++ Tricks](https://codeforces.com/blog/entry/74684)
- first two related to sorting
In order to sort a dynamic array, use `sort(v.begin(), v.end())` (or `sort(begin(v),end(v))`), whereas static arrays require `sort(arr, arr + N)` where $N$ is the number of elements to be sorted. The default sort function sorts the array in ascending order.
</CPPSection>

View file

@ -2,7 +2,7 @@
id: intro-greedy
title: Introduction to Greedy Algorithms
author: Michael Cao, Darren Yao
description: "Selecting the optimal choice at each step in your algorithm without looking at the solution space as a whole."
description: "Selecting the choice that seems to be the best at the moment at every step of your algorithm."
frequency: 2
---

View file

@ -2,7 +2,7 @@
id: pairs-tuples
title: Pairs & Tuples
author: Benjamin Qi, Nathan Wang, Darren Yao, Abutalib Namazov
description: "Introduction to pairs, which allow you to store two objects (possibly of different types) as a single unit, as well as tuples, which are a generalization of pairs."
description: "Storing two or more objects (possibly of different types) as a single unit."
prerequisites:
- intro-ds
---
@ -55,18 +55,17 @@ If you sort one of $x_i$ and $y_i$ without considering the other, the points wil
Example:
```cpp
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main() {
pair<string, int> myPair1 = make_pair("Testing", 123);
cout << myPair1.first << " " << myPair1.second << endl; // Testing 123
myPair1.first = "It is possible to edit pairs after declaring them";
cout << myPair1.first << " " << myPair1.second << endl;
pair<string, string> myPair2 = {"Testing", "curly braces"};
cout << myPair2.first << " " << myPair2.second << endl; // Testing curly braces
pair<string, int> myPair1 = make_pair("Testing", 123);
cout << myPair1.first << " " << myPair1.second << endl; // Testing 123
myPair1.first = "It is possible to edit pairs after declaring them";
cout << myPair1.first << " " << myPair1.second << endl;
pair<string, string> myPair2 = {"Testing", "curly braces"};
cout << myPair2.first << " " << myPair2.second << endl; // Testing curly braces
}
/* Output
@ -99,23 +98,20 @@ This is not frequently used by competitive programmers, but it is good to know a
Example:
```cpp
#include <iostream>
#include <tuple> /// needs additional library
#include <string>
#include <bits/stdc++.h>
using namespace std;
int main() {
int a = 3, b = 4, c = 5;
tuple<int, int, int> t = tie(a, b, c);
cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
get<0>(t) = 7;
cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
int a = 3, b = 4, c = 5;
tuple<int, int, int> t = tie(a, b, c);
cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
get<0>(t) = 7;
cout << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << endl;
tuple<string, string, int> tp2 = make_tuple("Hello", "world", 100);
string s1, s2; int x;
tie(s1, s2, x) = tp2;
cout << s1 << " " << s2 << " " << x << endl;
tuple<string, string, int> tp2 = make_tuple("Hello", "world", 100);
string s1, s2; int x;
tie(s1, s2, x) = tp2;
cout << s1 << " " << s2 << " " << x << endl;
}
/* Output
* 3 4 5
@ -139,12 +135,12 @@ Example from CPH:
using namespace std;
int main() {
vector<pair<int,int>> v;
v.push_back({1,5});
v.push_back({2,3});
v.push_back({1,2});
sort(v.begin(), v.end());
for (pair<int,int> p: v) cout << p.first << " " << p.second << "\n";
vector<pair<int,int>> v;
v.push_back({1,5});
v.push_back({2,3});
v.push_back({1,2});
sort(v.begin(), v.end());
for (pair<int,int> p: v) cout << p.first << " " << p.second << "\n";
}
/* Output:

View file

@ -8,7 +8,7 @@ description: "Evaluating a program's time complexity, or how fast your program r
<Resources>
<Resource source="IUSACO" title="3 - Algorithm Analysis">module is based off this</Resource>
<Resource source="CPH" title="2 - Time Complexity" starred>Intro and examples</Resource>
<Resource source="PAPS" title="5 - Time Complexity" starred>More in-depth. In particular, 5.2 gives a formal definition of Big O.</Resource>
<Resource source="PAPS" title="5 - Time Complexity">More in-depth. In particular, 5.2 gives a formal definition of Big O.</Resource>
</Resources>
<br />
@ -326,11 +326,21 @@ for i in range(m):
## Constant Factor
The **constant factor** of an algorithm refers to the coefficient of the complexity of an algorithm. If an algorithm runs in $O(kn)$ time, where $k$ is a constant and $n$ is the input size, then the "constant factor" would be $k$. (Ben - this is not a great definition)
The **constant factor** of an algorithm refers to the coefficient of the complexity of an algorithm. If an algorithm runs in $O(kn)$ time, where $k$ is a constant and $n$ is the input size, then the "constant factor" would be $k$.
<IncompleteSection />
<IncompleteSection>
Normally when using the big-O notation, we ignore the constant factor: $O(3n) = O(n)$. This is fine most of the time, but sometimes we have an algorithm that just barely gets TLE, perhaps by just a few hundred milliseconds. When this happens, it is worth optimizing the constant factor of our algorithm. For example, if our code currently runs in $O(n^2)$ time, perhaps we can modify our code to make it run in $O(n^2/32)$ by using a bitset. (Of course, with big-O notation, $O(n^2) = O(n^2/32)$.)
this is a terrible definition
</IncompleteSection>
Normally when using big-O notation, we ignore the constant factor: $O(3n) = O(n)$. This is fine most of the time, but sometimes we have an algorithm that just barely gets TLE, perhaps by just a few hundred milliseconds. When this happens, it is worth optimizing the constant factor of our algorithm. For example, if our code currently runs in $O(n^2)$ time, perhaps we can modify our code to make it run in $O(n^2/32)$ by using a bitset. (Of course, with big-O notation, $O(n^2) = O(n^2/32)$.)
<IncompleteSection>
fix math
</IncompleteSection>
For now, don't worry about how to optimize constant factors -- just be aware of them.

View file

@ -2,7 +2,7 @@
id: unordered
title: Unordered Maps & Sets
author: Darren Yao, Benjamin Qi
description: "An introduction to unordered maps and sets in multiple languages, two powerful data structures can help simplify bronze problems."
description: "?"
frequency: 2
prerequisites:
- pairs-tuples

40
content/3_Silver/2P.mdx Normal file
View file

@ -0,0 +1,40 @@
---
id: 2P
title: "Two Pointers"
author: Darren Yao
prerequisites:
description: "Refers to iterating two monotonic pointers across an array to search for a pair of indices satisfying some condition in linear time."
frequency: 2
---
import { Problem } from "../models";
export const problems = {
sample: [
new Problem("CSES", "Sum of Two Values", "1141", "Easy", false, []),
new Problem("CSES", "Subarray Sums I", "1660", "Easy", false, [], ""),
],
ad: [
new Problem("CSES", "Sum of Three Values", "1641", "Easy", false, [], ""),
new Problem("Silver", "Diamond Collector", "643", "Easy", false, ["2P", "Sorting"], ""),
new Problem("CF", "Books", "problemset/problem/279/B", "Easy", false, ["2P"]),
new Problem("CF", "Cellular Network", "problemset/problem/702/C", "Easy", false, []),
new Problem("CF", "USB vs. PS/2", "problemset/problem/762/B", "Easy", false, []),
new Problem("Silver", "Sleepy Cow Herding", "918", "Normal", false, ["2P", "Sorting"], ""),
new Problem("CF", "Garland", "problemset/problem/814/C", "Normal", false, []),
new Problem("CF", "Jury Meeting", "problemset/problem/853/B", "Normal", false, []),
],
};
<Problems problems={problems.sample} />
## Resources
<Resources>
<Resource source="CPH" title="8.1 - Two Pointers" starred>solutions to the problems above</Resource>
<Resource source="IUSACO" title="14.1 - Two Pointers"></Resource>
</Resources>
## Problems
<Problems problems={problems.ad} />

View file

@ -20,7 +20,6 @@ export const problems = {
new Problem("Silver", "Convention", "858", "Easy", false, [], "determine whether $M$ buses suffice if every cow waits at most $T$ minutes, use a greedy strategy (applies to next two problems as well)"),
new Problem("Silver", "Angry Cows", "594", "Easy", false, [], "check in $O(N)$ how many haybales you can destroy with fixed radius $R$"),
new Problem("Silver", "Social Distancing", "1038", "Normal", false, [], "check in $O(N+M)$ how many cows you can place with distance $D$"),
new Problem("Gold", "High Card Low Card", "573", "Normal", false, [], ""),
new Problem("Silver", "Loan Repayment", "991", "Hard", false, [], "requires some rather tricky analysis to speed up naive $O(N\log N)$ solution"),
new Problem("Gold", "Angry Cows", "597", "Hard", false, [], ""),
],

View file

@ -6,7 +6,7 @@ prerequisites:
- sorting-custom
- intro-ordered
- lambda
description: "More ways to write custom comparators in C++ and incorporating them into STL objects."
description: "Incorporating custom comparators into STL objects."
frequency: 1
---
@ -17,7 +17,7 @@ frequency: 1
<br />
What if we want to use a C++ `set` with the `Edge` struct that was defined in "Sorting with Custom Comparators"?
What if we want to use a C++ `set` with the `Edge` struct that was defined in [Sorting with Custom Comparators](./sorting-custom)?
## Operator Overloading

View file

@ -4,7 +4,7 @@ title: Depth First Search (DFS)
author: Siyong Huang
prerequisites:
- intro-graphs
description: "A way to recursively traverse through a graph."
description: "A way to recursively traverse a graph."
frequency: 4
---

View file

@ -26,10 +26,12 @@ export const problems = {
new Problem("Silver", "Why Did the Cow Cross the Road III", "716", "Normal", false, []),
new Problem("Silver", "Multiplayer Moo", "836", "Hard", false, []),
new Problem("Silver", "Snow Boots", "811", "Hard", false, []),
new Problem("Silver", "Mooyo Mooyo", "860", "Hard", false, []),
new Problem("Silver", "Mooyo Mooyo", "860", "Normal", false, [], ""),
],
};
<!-- Mooyo Mooyo: Not a sorting problem, but you can use sorting to simulate gravity. - Write a custom comparator which puts zeroes at the front and use `stable_sort` to keep the relative order of other elements the same. -->
<Problems problems={problems.sample} />
<br />

View file

@ -4,7 +4,7 @@ title: Functional Graphs
author: Siyong Huang
prerequisites:
- dfs
description: "Properties of a functional graphs, directed graphs in which every vertex has exactly one outgoing edge."
description: "Properties of functional graphs, directed graphs in which every vertex has exactly one outgoing edge."
frequency: 1
---
@ -16,14 +16,14 @@ export const problems = {
new Problem("CF", "Div 2 B - Badge", "contest/1020/problem/B", "Very Easy", false, ["Func Graph"], "Try to solve the problem in $O(N)$!"),
],
general: [
new Problem("Silver", "The Bovine Shuffle", "764", "Normal", false, ["Func Graph"], "Try to solve the problem in $O(N)$!"),
new Problem("Silver", "The Bovine Shuffle", "764", "Easy", false, ["Func Graph"], "Try to solve the problem in $O(N)$!"),
new Problem("CSES", "Planets Cycles", "1751", "Normal", false, ["Func Graph"], ""),
new Problem("Silver", "Swapity Swapity Swap", "1014", "Normal", false, ["Permutation"], ""),
new Problem("Codeforces", "Cooperative Game", "https://codeforces.com/contest/1137/problem/D", "Normal", false, ["Func Graph, Floyd's Algorithm"], "Implement Floyd's Algorithm! (You only actually need 3 friends to solve the problem!)"),
new Problem("CF", "Cooperative Game", "https://codeforces.com/contest/1137/problem/D", "Normal", false, ["Func Graph, Floyd's Algorithm"], "Implement Floyd's Algorithm! (You only actually need 3 friends to solve the problem!)"),
new Problem("POI", "Mafia", "https://szkopul.edu.pl/problemset/problem/w3YAoAT3ej27YeiaNWjK57_G/site/?key=statement", "Hard", false, ["Func Graph"], ""),
new Problem("POI", "Spies", "https://szkopul.edu.pl/problemset/problem/r6tMTfvQFPAEfQioYMCQndQe/site/?key=statement", "Hard", false, [], ""),
new Problem("POI", "Frog", "https://szkopul.edu.pl/problemset/problem/qDH9CkBHZKHY4vbKRBlXPrA7/site/?key=statement", "Hard", false, [], ""),
new Problem("ojuz", "Space Pirate", "JOI14_space_pirate", "Very Hard", false, ["Graphs"], "One of the most difficult problems of all time. Build a tree with a single back edge. Break into three cases: path -> other cycle, path -> subtree, path -> non-subtree. Then perform some black magic."),
new Problem("ojuz", "Space Pirate", "JOI14_space_pirate", "Insane", false, ["Graphs"], "One of the most difficult problems of all time. Build a tree with a single back edge. Break into three cases: path -> other cycle, path -> subtree, path -> non-subtree. Then perform some black magic."),
],
};
@ -41,7 +41,7 @@ This is also commonly referred to as a **successor graph**.
### Resources
<Resources>
<Resource source="CPH" title="16.3, 16.4 - Successor Graphs"></Resource>
<Resource source="CPH" title="16.3 Successor Graphs"></Resource>
</Resources>
### Implementation
@ -82,13 +82,12 @@ int main()
</LanguageSection>
## Tortoise and Hare (Floyd's Algorithm)
## Floyd's Algorithm
**Floyd's Algorithm**, also commonly referred to as the **Tortoise and Hare Algorithm**, is capable of detecting cycles in a functional graph in $O(N)$ time and $O(1)$ memory (not counting the graph itself)
### Resources
<Resources>
<Resource source="CPH" title="16.4 - Cycle Detection" starred></Resource>
<Resource source="Medium" title="The Tortoise and the Hare (Floyd's Algorithm)" url="https://medium.com/@tuvo1106/the-tortoise-and-the-hare-floyds-algorithm-87badf5f7d41"></Resource>
</Resources>

View file

@ -25,24 +25,23 @@ export const problems = {
new Problem("CSES", "Movie Festival II", "1632", "Easy", false, [], ""),
new Problem("CSES", "Stick Division", "1161", "Hard", false, [], ""),
],
usaco: [
new Problem("Silver", "Paired Up", "738", "Easy", false, ["2P", "Sorting"]),
new Problem("Silver", "Lemonade Line", "835", "?", false, [], ""),
new Problem("Silver", "Why ... (helpcross)", "714", "?", false, [], "first step: sort!"),
new Problem("Silver", "Berry Picking", "990", "?", false, [], ""),
new Problem("Silver", "Rest Stops", "810", "?", false, [], ""),
new Problem("Silver", "High Card Wins", "571", "?", false, [], ""),
],
other: [
new Problem("CSA", "Sure Bet", "sure-bet", "?", false, [], ""),
new Problem("CF", "Did you Mean...", "contest/860/problem/A", "?", false, [], ""),
new Problem("CF", "Bus", "contest/864/problem/C", "?", false, [], ""),
new Problem("CF", "Permutation", "contest/864/problem/D", "?", false, [], ""),
new Problem("CF", "Kayaking", "contest/863/problem/B", "?", false, [], "Huffman Coding?"),
new Problem("CF", "New Year and Three Musketeers", "contest/611/problem/E", "Hard", false, [], "needs maps"),
]
new Problem("Silver", "Paired Up", "738", "Easy", false, ["2P", "Sorting"]),
new Problem("Silver", "Lemonade Line", "835", "Easy", false, ["Sorting"], ""),
new Problem("Silver", "High Card Wins", "571", "Normal", false, [], ""),
new Problem("Gold", "High Card Low Card", "573", "Normal", false, [], ""),
new Problem("Silver", "Berry Picking", "990", "Normal", false, [], ""),
new Problem("Silver", "Why ... (helpcross)", "714", "Normal", false, ["Sorting"], ""),
new Problem("CSA", "Sure Bet", "sure-bet", "Normal", false, [], ""),
],
};
<!-- new Problem("Silver", "Rest Stops", "810", "?", false, [], ""), -->
<!-- new Problem("CF", "Did you Mean...", "contest/860/problem/A", "?", false, [], ""), -->
<!-- new Problem("CF", "Bus", "contest/864/problem/C", "?", false, [], ""), -->
<!-- new Problem("CF", "Permutation", "contest/864/problem/D", "?", false, [], ""), -->
<!-- new Problem("CF", "New Year and Three Musketeers", "contest/611/problem/E", "Hard", false, [], "needs maps"), -->
<Resources>
<Resource source="IUSACO" title="9 - Greedy Algorithms">Module is based off this.</Resource>
<Resource source="CPH" title="6 - Greedy Algorithms" starred></Resource>
@ -177,10 +176,6 @@ pw.close();
<Problems problems={problems.cses} />
## USACO Problems
<Problems problems={problems.usaco} />
## Other Problems
<Problems problems={problems.other} />

View file

@ -1,129 +0,0 @@
---
id: harder-ordered
title: "Harder Problems with Ordered Sets"
author: Benjamin Qi
prerequisites:
- custom-cpp-stl
description: "More advanced uses of ordered sets with example problems."
frequency: 2
---
import { Problem } from "../models";
export const problems = {
sample: [
new Problem("CSES", "Bit Inversions", "1188", "Normal", false, []),
],
general: [
new Problem("Silver", "Milk Measurement", "763", "Normal", false, []),
new Problem("Silver", "Convention II", "859", "Normal", false, []),
new Problem("Gold", "Snow Boots", "813", "Normal", false, []),
new Problem("CF", "Jury Marks", "contest/831/problem/C", "Hard", false, [], "Hard, would recommend skipping (1700 on CF)"),
new Problem("CF", "Mahmoud & Ehab & Function", "contest/862/problem/E", "Hard", false, [], "Hard, do not attempt until Gold/Plat (2100 on CF)"),
new Problem("CF", "Tournament", "contest/878/problem/C", "Very Hard", false, [], "First solve problem for $n$-th tournament only. Extremely hard, do not attempt (2700 on CF)"),
]
};
## Example: Using Iterators
<Problems problems={problems.sample} />
<Spoiler title="Solution">
```cpp
#include <bits/stdc++.h>
using namespace std;
#define sz(x) (x).size()
string s;
int m;
multiset<int> ans, ret;
void modify(int x) {
if (x == 0 || x == sz(s)) return;
auto it = ans.find(x);
if (it != end(ans)) {
int a = *prev(it), b = *next(it);
ret.erase(ret.find(x-a)), ret.erase(ret.find(b-x));
ret.insert(b-a);
ans.erase(it);
} else {
it = ans.insert(x);
int a = *prev(it), b = *next(it);
ret.erase(ret.find(b-a));
ret.insert(x-a), ret.insert(b-x);
}
}
int main() {
ios_base::sync_with_stdio(0); cin.tie(0);
cin >> s >> m;
ans.insert(0); ans.insert(sz(s));
for (int i = 0; i < sz(s)-1; ++i)
if (s[i] != s[i+1]) ans.insert(i+1);
for (auto it = ans.begin(); next(it) != ans.end(); it ++)
ret.insert(*next(it)-*it);
for (int i = 0; i < m; ++i) {
int x; cin >> x;
modify(x-1); modify(x);
cout << *ret.rbegin() << " ";
}
}
```
<br />
Note that `multiset` has a high constant factor, so replacing `ret` with an array and a `priority_queue` reduces the runtime by a factor of 2.
```cpp
#include <bits/stdc++.h>
using namespace std;
#define sz(x) (x).size()
string s;
int m;
set<int> ans;
priority_queue<int> ret;
int cnt[200005];
void ad(int x) { cnt[x] ++; ret.push(x); }
void modify(int x) {
if (x == 0 || x == sz(s)) return;
auto it = ans.find(x);
if (it != end(ans)) {
int a = *prev(it), b = *next(it); ans.erase(it);
cnt[x-a] --, cnt[b-x] --; ad(b-a);
} else {
it = ans.insert(x).first;
int a = *prev(it), b = *next(it);
cnt[b-a] --, ad(x-a), ad(b-x);
}
}
int main() {
ios_base::sync_with_stdio(0); cin.tie(0);
cin >> s >> m;
ans.insert(0); ans.insert(sz(s));
for (int i = 0; i < sz(s)-1; ++i)
if (s[i] != s[i+1]) ans.insert(i+1);
for (auto it = ans.begin(); next(it) != ans.end(); it ++)
ad(*next(it)-*it);
for (int i = 0; i < m; ++i) {
int x; cin >> x;
modify(x-1); modify(x);
while (!cnt[ret.top()]) ret.pop();
cout << ret.top() << " ";
}
}
```
</Spoiler>
<IncompleteSection />
## Problems
<Problems problems={problems.general} />

View file

@ -0,0 +1,15 @@
---
id: harder-ordered
title: "Harder Problems with Ordered Sets"
author: Benjamin Qi
prerequisites:
- custom-cpp-stl
description: "More advanced uses of ordered sets with example problems."
frequency: 2
---
import { Problem } from "../models";
export const problems = {
};

View file

@ -4,7 +4,7 @@ title: "Introduction to Ordered Sets"
author: Darren Yao, Benjamin Qi
prerequisites:
- unordered
description: "A data structure that supports quick insertion and deletion by maintaining keys in sorted order."
description: "Data structures that maintain keys in sorted order."
frequency: 2
---
@ -15,8 +15,25 @@ export const problems = {
new Problem("CSES", "Concert Tickets", "1091", "Easy", false, ["iterators"], "just do upper_bound"),
new Problem("CSES", "Traffic Lights", "1163", "Normal", false, ["set"], "just insert into set one at a time"),
],
sample: [
new Problem("CSES", "Bit Inversions", "1188", "Normal", false, []),
],
general: [
new Problem("Silver", "Milk Measurement", "763", "Normal", false, []),
new Problem("Silver", "Convention II", "859", "Normal", false, []),
new Problem("Gold", "Snow Boots", "813", "Normal", false, []),
new Problem("CF", "Jury Marks", "contest/831/problem/C", "Hard", false, [], "Hard, would recommend skipping (1700 on CF)"),
new Problem("CF", "Mahmoud & Ehab & Function", "contest/862/problem/E", "Hard", false, [], "Hard, do not attempt until Gold/Plat (2100 on CF)"),
new Problem("CF", "Tournament", "contest/878/problem/C", "Very Hard", false, [], "First solve problem for $n$-th tournament only. Extremely hard, do not attempt (2700 on CF)"),
]
};
<Warning>
This is **not** built into Python. The Python [OrderedDict](https://docs.python.org/3/library/collections.html#collections.OrderedDict) stores keys in the same order as they were inserted in, **not** in sorted order.
</Warning>
<Resources>
<Resource source="IUSACO" title="4.3 - Sets & Maps">module is based off this</Resource>
<Resource source="CPH" title="4.2 to 4.4 - Data Structures" starred>sets, maps, set iterators</Resource>
@ -26,15 +43,16 @@ export const problems = {
In **ordered** sets and maps, the entries are sorted in order of key. Insertions, deletions, and searches are all $O(\log N)$, where $N$ is the number of elements in the set or map. Accessing or removing the next key higher or lower than some input $k$ is also supported.
(**not** the same as [OrderedDict](https://docs.python.org/3/library/collections.html#collections.OrderedDict) in Python ...)
## Ordered Sets
<LanguageSection>
<CPPSection>
As well as those supported by `unordered_set`, the ordered set also allows four additional operations: `begin()`, which returns an iterator to the lowest element in the set, `end()`, which returns an iterator to the highest element in the set, `lower_bound`, which returns an iterator to the least element greater than or equal to some element `k`, and `upper_bound`, which returns an iterator to the least element strictly greater than some element `k`.
In addition to the `unordered_set` operations mentioned in the prerequisite module, the ordered `set` also allows:
- `lower_bound`: returns an iterator to the least element greater than or equal to some element `k`
- `upper_bound`: returns an iterator to the least element strictly greater than some element `k`.
```cpp
set<int> s;
@ -77,7 +95,7 @@ System.out.println(set.higher(23); // ERROR, no such element exists
</LanguageSection>
One limitation of the ordered set is that we can't efficiently access the $k^{th}$ largest element in the set, or find the number of elements in the set greater than some arbitrary $x$. These operations can be handled using a data structure called an **order statistic tree** (see Gold - Point Update Range Sum).
One limitation of the ordered set is that we can't efficiently access the $k^{th}$ largest element in the set, or find the number of elements in the set greater than some arbitrary $x$. These operations can be handled using a data structure called an [order statistic tree](../gold/PURS#order-statistic-tree).
## Ordered Maps
@ -85,7 +103,10 @@ One limitation of the ordered set is that we can't efficiently access the $k^{th
<CPPSection>
The ordered map supports all of the operations that an `unordered_map` supports, and additionally supports `lower_bound` and `upper_bound`, returning the iterator pointing to the lowest entry not less than the specified key, and the iterator pointing to the lowest entry strictly greater than the specified key respectively.
In addition to the `unordered_map` operations mentioned in the prerequisite module, the ordered `map` also allows:
- `lower_bound`: returns the iterator pointing to the lowest entry not less than the specified key
- `upper_bound`: returns the iterator pointing to the lowest entry strictly greater than the specified key respectively.
```cpp
map<int, int> m;
@ -133,7 +154,10 @@ A **multiset** is a sorted set that allows multiple copies of the same element.
<CPPSection>
In addition to all of the regular set operations, the multiset `count()` method returns the number of times an element is present in the multiset. However, this method takes time **linear** in the number of matches so you shouldn't use it in a contest. The `begin()`, `end()`, `lower_bound()`, and `upper_bound()` operations work the same way they do in the normal sorted set. **Warning:** If you want to remove a value *once*, make sure to use `multiset.erase(multiset.find(val))` rather than `multiset.erase(val)`. The latter will remove *all* instances of `val`.
In addition to all of the regular set operations,
- the `count()` method returns the number of times an element is present in the multiset. However, this method takes time **linear** in the number of matches so you shouldn't use it in a contest.
- If you want to remove a value *once*, make sure to use `multiset.erase(multiset.find(val))` rather than `multiset.erase(val)`. The latter will remove *all* instances of `val`.
```cpp
@ -187,11 +211,26 @@ static void remove(int x){
</LanguageSection>
## Using Iterators
<LanguageSection>
<CPPSection>
next(), prev(), ++, --
</CPPSection>
</LanguageSection>
<IncompleteSection />
## Priority Queues
A **priority queue** supports the following operations: insertion of elements, deletion of the element considered highest priority, and retrieval of the highest priority element, all in $O(\log N)$ time according to the number of elements in the priority queue. Like sets, priority is based on a **comparator function**.
Of course, all of these functions are supported by multisets, but priority queues are simpler (so they are much faster).
Of course, all of these functions are supported by multisets, but priority queues are simpler and faster.
<LanguageSection>
@ -235,22 +274,118 @@ pq.add(6); // [7, 6, 5]
</LanguageSection>
## Using Iterators
## Introductory Problems
<Problems problems={problems.standard} />
## Harder Example: Bit Inversions
<Problems problems={problems.sample} />
### Solution
<Spoiler title="Solution">
<LanguageSection>
<CPPSection>
next(), prev(), ++, --
```cpp
#include <bits/stdc++.h>
using namespace std;
#define sz(x) (x).size()
string s;
int m;
multiset<int> ans, ret;
void modify(int x) {
if (x == 0 || x == sz(s)) return;
auto it = ans.find(x);
if (it != end(ans)) {
int a = *prev(it), b = *next(it);
ret.erase(ret.find(x-a)), ret.erase(ret.find(b-x));
ret.insert(b-a);
ans.erase(it);
} else {
it = ans.insert(x);
int a = *prev(it), b = *next(it);
ret.erase(ret.find(b-a));
ret.insert(x-a), ret.insert(b-x);
}
}
int main() {
ios_base::sync_with_stdio(0); cin.tie(0);
cin >> s >> m;
ans.insert(0); ans.insert(sz(s));
for (int i = 0; i < sz(s)-1; ++i)
if (s[i] != s[i+1]) ans.insert(i+1);
for (auto it = ans.begin(); next(it) != ans.end(); it ++)
ret.insert(*next(it)-*it);
for (int i = 0; i < m; ++i) {
int x; cin >> x;
modify(x-1); modify(x);
cout << *ret.rbegin() << " ";
}
}
```
<br />
Note that `multiset` has a high constant factor, so replacing `ret` with an array and a `priority_queue` reduces the runtime by a factor of 2.
```cpp
#include <bits/stdc++.h>
using namespace std;
#define sz(x) (int)(x).size()
string s;
int m;
set<int> ans;
priority_queue<int> ret;
int cnt[200005];
void ad(int x) { cnt[x] ++; ret.push(x); }
void modify(int x) {
if (x == 0 || x == sz(s)) return;
auto it = ans.find(x);
if (it != end(ans)) {
int a = *prev(it), b = *next(it); ans.erase(it);
cnt[x-a] --, cnt[b-x] --; ad(b-a);
} else {
it = ans.insert(x).first;
int a = *prev(it), b = *next(it);
cnt[b-a] --, ad(x-a), ad(b-x);
}
}
int main() {
ios_base::sync_with_stdio(0); cin.tie(0);
cin >> s >> m;
ans.insert(0); ans.insert(sz(s));
for (int i = 0; i < sz(s)-1; ++i)
if (s[i] != s[i+1]) ans.insert(i+1);
for (auto it = ans.begin(); next(it) != ans.end(); it ++)
ad(*next(it)-*it);
for (int i = 0; i < m; ++i) {
int x; cin >> x;
modify(x-1); modify(x);
while (!cnt[ret.top()]) ret.pop();
cout << ret.top() << " ";
}
}
```
</CPPSection>
</LanguageSection>
<IncompleteSection />
</Spoiler>
## Standard
## Harder Problems
<Problems problems={problems.standard} />
<Problems problems={problems.general} />

View file

@ -1,89 +0,0 @@
---
id: sliding
title: "Sliding Window"
author: Darren Yao, Benjamin Qi
prerequisites:
- stacks-queues
- intro-ordered
description: "Moving a subarray across an array to efficently compute information."
frequency: 2
---
import { Problem } from "../models";
export const problems = {
sample: [
new Problem("CSES", "Sum of Two Values", "1141", "Easy", false, []),
],
slide: [
new Problem("CSES", "Playlist", "1141", "Easy", false, [],"classic example of 2P"),
],
general: [
new Problem("CSES", "Subarray Sums I", "1660", "Easy", false, [], ""),
new Problem("CSES", "Sliding Median", "1076", "Easy", false, [], ""),
new Problem("CSES", "Sliding Cost", "1077", "Hard", false, [], ""),
new Problem("CSES", "Max Subarray Sum II", "1644", "Normal", false, [], ""),
new Problem("Silver", "Diamond Collector", "643", "Easy", false, ["2P", "Sorting"], ""),
new Problem("Silver", "Sleepy Cow Herding", "918", "Normal", false, ["2P", "Sorting"], ""),
new Problem("Gold", "Haybale Feast", "767", "Normal", false, ["Set", "Sliding Window"]),
new Problem("CF", "Books", "problemset/problem/279/B", "Normal", false, []),
new Problem("CF", "Cellular Network", "problemset/problem/702/C", "Normal", false, []),
new Problem("CF", "USB vs. PS/2", "problemset/problem/762/B", "Normal", false, []),
new Problem("CF", "K-Good Segment", "problemset/problem/616/D", "Normal", false, []),
new Problem("CF", "Garland", "problemset/problem/814/C", "Normal", false, []),
new Problem("CF", "Jury Meeting", "problemset/problem/853/B", "Normal", false, []),
new Problem("Plat", "Fort Moo", "600", "Very Hard", false, ["Sliding Window"]),
],
qs: [
new Problem("YS","Queue Composite","queue_operate_all_composite","Hard",true,[],""),
],
};
## Two Pointers
<Problems problems={problems.sample} />
Two pointers refers to iterating two monotonic pointers across an array to search for a pair of indices satisfying some condition in linear time.
<Resources>
<Resource source="CPH" title="8.1 - Two Pointers"></Resource>
<Resource source="IUSACO" title="14.1 - Two Pointers"></Resource>
</Resources>
### Implementation
<IncompleteSection />
## Sliding Window
<Problems problems={problems.slide} />
Let's envision a **sliding window** (or constant size subarray) of size $K$ moving left to right along an array, $a$.
For each position of the window, we want to compute some information. For example, we could store an ordered set of integers representing the integers inside the window. If the window currently spans the range $i \dots j$, we observe that moving the range forward to $i+1 \dots j+1$ only removes $a_i$ and adds $a_{j+1}$ to the window. We can support these two operations and query for the minimum / maximum in the set in $O(\log N)$.
To compute the sum in the range, instead of using a set, we can store a variable $s$ representing the sum. As we move the window forward, we update $s$ by subtracting $a_i$ from $s$ and adding $a_{j+1}$ to $s$.
<Resources>
<Resource source="Medium" title="Introduction to Sliding Window Algorithms" url="https://levelup.gitconnected.com/an-introduction-to-sliding-window-algorithms-5533c4fe1cc7"> </Resource>
<Resource source="GFG" title="Window Sliding Technique" url="window-sliding-technique"> </Resource>
</Resources>
### Implementation
<IncompleteSection />
### Problems
<Problems problems={problems.general} />
## Sliding Window Minimum in $O(N)$
<Resources>
<Resource source="cp-algo" title="Minimum stack / Minimum queue" url="data_structures/stack_queue_modification.html" starred>Mentions two ways to solve this (both are important)!</Resource>
</Resources>
In particular, the second method allows us to solve the following generalization in linear time as well:
<Problems problems={problems.qs} />

View file

@ -6,7 +6,7 @@ author: Darren Yao, Siyong Huang, Michael Cao, Benjamin Qi
prerequisites:
- pairs-tuples
- lambda
description: "Both Java and C++ have built-in functions for sorting. However, if we use custom objects, or if we want to sort elements in a different order, then we'll need to use a custom comparator."
description: "If we use custom objects or if we want to sort elements in an order other than the default, then we'll need to define a custom comparator."
---
import { Problem } from "../models";
@ -20,7 +20,6 @@ export const problems = {
new Problem("Silver", "Lifeguards", "786", "Easy", false, [], "Similar to above."),
new Problem("Silver", "Rental Service", "787", "Easy", false, [], ""),
new Problem("Silver", "Mountains", "896", "Easy", false, [], ""),
new Problem("Silver", "Mooyo Mooyo", "860", "Easy", false, [], "Not a sorting problem, but you can use sorting to simulate gravity. - Write a custom comparator which puts zeroes at the front and use `stable_sort` to keep the relative order of other elements the same."),
new Problem("Gold", "Splitting the Field", "645", "Normal", false, [], ""),
new Problem("Silver", "Triangles", "1015", "Hard", false, [], ""),
new Problem("Silver", "Meetings", "967", "Very Hard", false, [], ""),
@ -28,7 +27,8 @@ export const problems = {
};
<Resources>
<Resource source="IUSACO" title="8 - Sorting & Comparators"></Resource>
<Resource source="IUSACO" title="8 - Sorting & Comparators">partially based off this</Resource>
<Resource source="CPH" title="3.2 - User-Defined Structs, Comparison Functions">short overflow of what this module will cover</Resource>
</Resources>
<br />
@ -55,7 +55,7 @@ After sorting, it should look like
2 3 10
```
With C++, the easiest method is to use nested pairs or a `vector` of `array<int,3>` or `vector<int>`.
With C++, the easiest method is to use a `vector` of nested `pair`s:
```cpp
#include <bits/stdc++.h>
@ -76,6 +76,8 @@ int main() {
}
```
or a `vector` of `array<int,3>`s or `vector<int>`s:
```cpp
int main() {
int M = 4;
@ -91,10 +93,10 @@ int main() {
In Python, we can use a list of lists.
But in Java, we can't immediately sort an arraylist of arraylists. What should we do?
But in Java, we can't sort an `ArrayList` of `ArrayList`s without writing some additional code. What should we do?
- If we only stored the edge weights and sorted them, we would have a sorted list of edge weights, but it would be impossible to tell which weights corresponded to which edges.
- However, if we create a **class** (or struct) representing the edges and define a **custom comparator** to sort them by weight, we can sort the edges in ascending order while also keeping track of their endpoints.
- However, if we create a **class** representing the edges and define a **custom comparator** to sort them by weight, we can sort the edges in ascending order while also keeping track of their endpoints.
## Classes
@ -105,6 +107,10 @@ First, we need to define a **class** that represents what we want to sort. In ou
<CPPSection>
### C++
A C++ `struct` is the same as a class in C++, but all members are public by default.
```cpp
#include <bits/stdc++.h>
using namespace std;
@ -113,6 +119,13 @@ struct Edge {
int a,b,w;
};
/* alternatively,
class Edge {
public:
int a,b,w;
};
*/
int main() {
int M = 4;
vector<Edge> v;
@ -188,10 +201,6 @@ Normally, sorting functions rely on moving objects with a lower value in front o
<CPPSection>
<Resources>
<Resource source="CPH" title="3.2 - User-Defined Structs, Comparison Functions" starred></Resource>
</Resources>
What a comparator does is compare two objects as follows, based on our comparison criteria:
- If object $x$ is less than object $y$, return `true`
@ -201,7 +210,7 @@ Essentially, the comparator determines whether object $x$ belongs to the left of
In addition to returning the correct answer, comparators should also satisfy the following conditions:
- The function must be consistent with respect to reversing the order of the arguments: if $x \neq y$ and `compare(x, y)`is `true`, then `compare(y, x)` should be `false` and vice versa.
- The function must be consistent with respect to reversing the order of the arguments: if $x \neq y$ and `compare(x, y)` is `true`, then `compare(y, x)` should be `false` and vice versa.
- The function must be transitive. If `compare(x, y)` is true and `compare(y, z)` is true, then `compare(x, z)` should also be true. If the first two compare functions both return `false`, the third must also return `false`.
### Method 1: Overloading the Less Than Operator
@ -209,7 +218,7 @@ In addition to returning the correct answer, comparators should also satisfy the
This is the easiest to implement. However, it only works for objects (not primitives) and it doesn't allow you to define multiple ways to compare the same type of class.
In the context of Wormhole Sort (note the use of
[const T&](https://stackoverflow.com/questions/11805322/why-should-i-use-const-t-instead-of-const-t-or-t)):
[const Edge&](https://stackoverflow.com/questions/11805322/why-should-i-use-const-t-instead-of-const-t-or-t)):
```cpp
#include <bits/stdc++.h>
@ -278,7 +287,7 @@ int main() {
```
We can also use lambda expressions in C++11 or above:
We can also use [lambda expressions](../intro/lambda) in C++11 or above:
```cpp
sort(begin(v),end(v),[](const Edge& x, const Edge& y) { return x.w < y.w; });

View file

@ -1,6 +1,6 @@
---
id: intro-dp
title: "Introduction to Dynamic Programming"
title: "Introduction to Dynamic Programming (DP)"
author: Michael Cao
prerequisites:
- complete-search
@ -51,11 +51,17 @@ export const problems = {
],
}
Dynamic Programming is an important algorithmic technique in competitive programming that appears at all levels of competition.
**Dynamic Programming** (DP) is an important algorithmic technique in competitive programming that appears at all levels of competition.
By breaking down the full task into sub-problems, Dynamic Programming avoids the redundant computations of brute force solutions.
<IncompleteSection>
Although it is not too difficult to grasp the general ideas behind Dynamic Programming, or DP, the technique can be used in a diverse range of problems and is a must-know idea for competitors in the USACO gold division.
What do you mean by "all levels"? Certainly doesn't appear in silver ...
</IncompleteSection>
By breaking down the full task into sub-problems, DP avoids the redundant computations of brute force solutions.
Although it is not too difficult to grasp the general ideas behind DP, the technique can be used in a diverse range of problems and is a must-know idea for competitors in the USACO gold division.
## Introductory Resources

View file

@ -133,49 +133,51 @@ Don't just dive into trying to figure out a DP state and transitions -- make som
<Spoiler title="Ostap & Tree">
Solution described by editorial is terrible, but we can do better! This runs in $O(NK)$ time. (proof?)
```cpp
vmi yes[101], no[101];
int n,k;
vi adj[MX];
void dfs(int x, int y) {
yes[x] = no[x] = {1}; // black, not black
// dist of closest good vertex
// or dist of farthest bad vertex
auto ad = [](vmi& a, int b, mi c) {
while (sz(a) <= b) a.pb(0);
a[b] += c;
};
trav(t,adj[x]) if (t != y) {
dfs(t,x);
yes[t].insert(begin(yes[t]),0);
no[t].insert(begin(no[t]),0);
if (sz(no[t]) > k+1) no[t].pop_back();
vmi YES, NO;
F0R(i,sz(yes[x])) F0R(j,sz(yes[t])) ad(YES,min(i,j),yes[x][i]*yes[t][j]);
F0R(i,sz(no[x])) F0R(j,sz(no[t])) ad(NO,max(i,j),no[x][i]*no[t][j]);
auto yesNo = [&](vmi good, vmi bad) {
F0R(i,sz(good)) F0R(j,sz(bad)) {
if (i+j <= k) ad(YES,i,good[i]*bad[j]);
else ad(NO,j,good[i]*bad[j]);
}
};
yesNo(yes[x],no[t]); yesNo(yes[t],no[x]);
swap(yes[x],YES); swap(no[x],NO);
}
yes[x] = no[x] = {1}; // black, not black
// dist of closest good vertex
// or dist of farthest bad vertex
auto ad = [](vmi& a, int b, mi c) {
while (sz(a) <= b) a.pb(0);
a[b] += c;
};
trav(t,adj[x]) if (t != y) {
dfs(t,x);
yes[t].insert(begin(yes[t]),0);
no[t].insert(begin(no[t]),0);
if (sz(no[t]) > k+1) no[t].pop_back();
vmi YES, NO;
F0R(i,sz(yes[x])) F0R(j,sz(yes[t])) ad(YES,min(i,j),yes[x][i]*yes[t][j]);
F0R(i,sz(no[x])) F0R(j,sz(no[t])) ad(NO,max(i,j),no[x][i]*no[t][j]);
auto yesNo = [&](vmi good, vmi bad) {
F0R(i,sz(good)) F0R(j,sz(bad)) {
if (i+j <= k) ad(YES,i,good[i]*bad[j]);
else ad(NO,j,good[i]*bad[j]);
}
};
yesNo(yes[x],no[t]); yesNo(yes[t],no[x]);
swap(yes[x],YES); swap(no[x],NO);
}
}
int main() {
setIO(); re(n,k);
F0R(i,n-1) {
int a,b; re(a,b);
adj[a].pb(b), adj[b].pb(a);
}
dfs(1,0);
mi ans = 0;
trav(t,yes[1]) ans += t;
ps(ans);
// you should actually read the stuff at the bottom
setIO(); re(n,k);
F0R(i,n-1) {
int a,b; re(a,b);
adj[a].pb(b), adj[b].pb(a);
}
dfs(1,0);
mi ans = 0;
trav(t,yes[1]) ans += t;
ps(ans);
// you should actually read the stuff at the bottom
}
```

View file

@ -14,6 +14,9 @@ export const problems = {
three: [
new Problem("Gold", "3SUM", "994", "Normal", false, [], ""),
],
four: [
new Problem("CSES", "Sum of Four Values", "1642", "Normal", false, [], ""),
],
};
<Resources>
@ -104,9 +107,9 @@ You're supposed to use array since values are small :|
using namespace std;
void setIO(string name) {
ios_base::sync_with_stdio(0); cin.tie(0);
freopen((name+".in").c_str(),"r",stdin);
freopen((name+".out").c_str(),"w",stdout);
ios_base::sync_with_stdio(0); cin.tie(0);
freopen((name+".in").c_str(),"r",stdin);
freopen((name+".out").c_str(),"w",stdout);
}
@ -118,27 +121,31 @@ long long ans[5000][5000];
vector<int> A;
int main() {
setIO("threesum");
cin >> N >> Q;
A.resize(N); for (int i = 0; i < N; ++i) cin >> A[i];
for (int i = 0; i < N; ++i) {
gp_hash_table<int,int> g({},{},{},{},{1<<13});
// initialize with certain capacity, must be power of 2
for (int j = i+1; j < N; ++j) {
int res = -A[i]-A[j];
auto it = g.find(res);
if (it != end(g)) ans[i][j] = it->second;
g[A[j]] ++;
}
}
for (int i = N-1; i >= 0; --i) for (int j = i+1; j < N; ++j)
ans[i][j] += ans[i+1][j]+ans[i][j-1]-ans[i+1][j-1];
for (int i = 0; i < Q; ++i) {
int a,b; cin >> a >> b;
cout << ans[a-1][b-1] << "\n";
}
// you should actually read the stuff at the bottom
setIO("threesum");
cin >> N >> Q;
A.resize(N); for (int i = 0; i < N; ++i) cin >> A[i];
for (int i = 0; i < N; ++i) {
gp_hash_table<int,int> g({},{},{},{},{1<<13});
// initialize with certain capacity, must be power of 2
for (int j = i+1; j < N; ++j) {
int res = -A[i]-A[j];
auto it = g.find(res);
if (it != end(g)) ans[i][j] = it->second;
g[A[j]] ++;
}
}
for (int i = N-1; i >= 0; --i) for (int j = i+1; j < N; ++j)
ans[i][j] += ans[i+1][j]+ans[i][j-1]-ans[i+1][j-1];
for (int i = 0; i < Q; ++i) {
int a,b; cin >> a >> b;
cout << ans[a-1][b-1] << "\n";
}
// you should actually read the stuff at the bottom
}
```
<IncompleteSection />
<IncompleteSection />
## Problems
<Problems problems={problems.four} />

View file

@ -31,10 +31,12 @@ export const problems = {
<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>
<Resource source="PAPS" title="16.1, 16.2, 16.4 - Number Theory"></Resource>
</Resources>
<!-- <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>
-->
## Prime Factorization
<Problems problems={problems.sample} />
@ -204,7 +206,13 @@ We'll only consider **prime** moduli here. Division can be performed using modul
#### With Exponentiation
To find the modular inverse of some number, simply raise it to the power of $\mathrm{MOD} - 2$, where $\mathrm{MOD}$ is the modulus being used, using the function described above. (The reasons for raising the number to $\mathrm{MOD} - 2$ can be explained with **Fermat's Little Theorem**, but we will not explain the theorem here).
To find the modular inverse of some number, simply raise it to the power of $\mathrm{MOD} - 2$, where $\mathrm{MOD}$ is the modulus being used, using the function described above. The reasons for raising the number to $\mathrm{MOD} - 2$ can be explained with **Fermat's Little Theorem**.
<IncompleteSection>
explain theorem?
</IncompleteSection>
The modular inverse is the equivalent of the reciprocal in real-number arithmetic; to divide $a$ by $b$, multiply $a$ by the modular inverse of $b$.
@ -212,12 +220,10 @@ Because it takes $\mathcal{O}(\log \mathrm{MOD})$ time to compute a modular inve
Also, one must always ensure that they do not attempt to divide by 0. Be aware that after applying modulo, a nonzero number can become zero, so be very careful when dividing by non-constant values.
<IncompleteSection />
#### With Extended Euclidean Algorithm
<Optional>
See the module in the [Advanced](../adv/extend-euclid) section.
</Optional>

View file

@ -3,8 +3,8 @@ id: mst
title: "Minimum Spanning Trees"
author: Benjamin Qi
prerequisites:
- Gold - Shortest Paths with Non-Negative Edge Weights
- Gold - Disjoint Set Union
- sp
- dsu
description: "A subset of the edges of a connected, undirected, edge-weighted graph that connects all the vertices to each other of minimum total weight, where no cycles are allowed."
frequency: 2
---

View file

@ -4,7 +4,7 @@ title: "Point Update Range Sum"
author: Benjamin Qi
prerequisites:
- prefix-sums
description: "Introducing Segment Trees, Binary Indexed Trees, and Indexed Sets (C++ only)."
description: "Introduces Segment Tree, Binary Indexed Tree, and Order Statistic Tree (C++ only)."
frequency: 3
---
@ -147,7 +147,7 @@ Suppose that we want a data structure that supports all the operations as a `set
- `order_of_key(x)`: counts the number of elements in the set that are strictly less than `x`.
- `find_by_order(k)`: similar to `find`, returns the iterator corresponding to the `k`-th lowest element in the set (0-indexed).
### Indexed Set
### Order Statistic Tree
Luckily, such a built-in data structure already exists in C++.

133
content/4_Gold/Queues.mdx Normal file
View file

@ -0,0 +1,133 @@
---
id: queues
title: Queues
author: Darren Yao
description: "Two data structures to efficently add and remove the first and last element."
prerequisites:
- intro-ds
- sliding
---
import { Problem } from "../models";
export const problems = {
ys: [
new Problem("YS","Persistent Queue","persistent_queue","Normal",false,["DFS"],""),
new Problem("YS","Queue Composite","queue_operate_all_composite","Hard",true,[],""),
],
sam: [
new Problem("LC", "Sliding Window Maximum", "sliding-window-maximum", "Easy", false, [], ""),
],
};
<Resources>
<Resource source="CPH" title="4.5 - Queues, Deques"></Resource>
<Resource source="PAPS" title="3.2, 6.3 - Queues"></Resource>
</Resources>
## Queues
A queue is a First In First Out (FIFO) data structure that supports three operations, all in $O(1)$ time.
<LanguageSection>
<CPPSection>
### [C++](http://www.cplusplus.com/reference/queue/queue/)
- `push`: insertion at the back of the queue
- `pop`: deletion from the front of the queue
- `front`: which retrieves the element at the front without removing it.
```cpp
queue<int> q;
q.push(1); // [1]
q.push(3); // [3, 1]
q.push(4); // [4, 3, 1]
q.pop(); // [4, 3]
cout << q.front() << endl; // 3
```
</CPPSection>
<JavaSection>
### Java
- `add`: insertion at the back of the queue
- `poll`: deletion from the front of the queue
- `peek`: which retrieves the element at the front without removing it
Java doesn't actually have a `Queue` class; it's only an interface. The most commonly used implementation is the `LinkedList`, declared as follows:
```java
Queue<Integer> q = new LinkedList<Integer>();
q.add(1); // [1]
q.add(3); // [3, 1]
q.add(4); // [4, 3, 1]
q.poll(); // [4, 3]
System.out.println(q.peek()); // 3
```
</JavaSection>
</LanguageSection>
## Deques
A **deque** (usually pronounced "deck") stands for double ended queue and is a combination of a stack and a queue, in that it supports $O(1)$ insertions and deletions from both the front and the back of the deque. Not very common in Bronze / Silver.
<LanguageSection>
<CPPSection>
### [C++](http://www.cplusplus.com/reference/deque/deque/)
The four methods for adding and removing are `push_back`, `pop_back`, `push_front`, and `pop_front`.
```cpp
deque<int> d;
d.push_front(3); // [3]
d.push_front(4); // [4, 3]
d.push_back(7); // [4, 3, 7]
d.pop_front(); // [3, 7]
d.push_front(1); // [1, 3, 7]
d.pop_back(); // [1, 3]
```
(important: you can also access like array ...)
</CPPSection>
<JavaSection>
### Java
In Java, the deque class is called `ArrayDeque`. The four methods for adding and removing are `addFirst` , `removeFirst`, `addLast`, and `removeLast`.
```java
ArrayDeque<Integer> deque = new ArrayDeque<Integer>();
deque.addFirst(3); // [3]
deque.addFirst(4); // [4, 3]
deque.addLast(7); // [4, 3, 7]
deque.removeFirst(); // [3, 7]
deque.addFirst(1); // [1, 3, 7]
deque.removeLast(); // [1, 3]
```
</JavaSection>
</LanguageSection>
## Sliding Window Minimum in $O(N)$
<Problems problems={problems.sam} />
<Resources>
<Resource source="CPH" title="8.3 - Sliding Window Minimum"></Resource>
<Resource source="cp-algo" title="Minimum stack / Minimum queue" url="data_structures/stack_queue_modification.html" starred>Mentions two ways to solve this (both are important)!</Resource>
</Resources>
## Problems
<Problems problems={problems.ys} />

View file

@ -112,4 +112,6 @@ just to be safe.
<Problems problems={problems.apsp} />
(more?)
(more?)
<IncompleteSection />

View file

@ -22,9 +22,11 @@ export const problems = {
],
};
Given a static array $A[1],A[2],\ldots,A[N]$, you want to answer queries in the form $A[l]\ominus A[l+1]\ominus \cdots \ominus A[r]$ where $\ominus$ denotes any associative operation.
With $O(N\log N)$ time preprocessing, we can get $O(1)$ queries.
Given a static array $A[1],A[2],\ldots,A[N]$, you want to answer queries in the form
$$
A[l]\ominus A[l+1]\ominus \cdots \ominus A[r]
$$
where $\ominus$ denotes any associative operation. With $O(N\log N)$ time preprocessing, we can get $O(1)$ time queries!
## [Range Minimum Query](https://en.wikipedia.org/wiki/Range_minimum_query)

View file

@ -0,0 +1,73 @@
---
id: sliding
title: "Sliding Window"
author: Darren Yao, Benjamin Qi
prerequisites:
- intro-ordered
- 2P
description: "Maintaining data over consecutive subarrays."
frequency: 2
---
import { Problem } from "../models";
export const problems = {
constantSam: [
new Problem("LC", "Sliding Window Maximum", "sliding-window-maximum", "Easy", false, [], ""),
],
constant: [
new Problem("CSES", "Max Subarray Sum II", "1644", "Normal", false, ["prefix-sums"], ""),
new Problem("CSES", "Sliding Median", "1076", "Normal", false, [], ""),
new Problem("CSES", "Sliding Cost", "1077", "Hard", false, [], ""),
],
sam: [
new Problem("CSES", "Playlist", "1141", "Easy", false, ["2P"], ""),
],
general: [
new Problem("CF", "K-Good Segment", "problemset/problem/616/D", "Easy", false, []),
new Problem("Gold", "Haybale Feast", "767", "Easy", false, ["Set", "Sliding Window"]),
new Problem("Plat", "Fort Moo", "600", "Hard", false, ["Sliding Window"]),
]
};
## Sliding Window
<Problems problems={problems.constantSam} />
From CPH:
> A sliding window is a constant-size subarray that moves from left to right
through the array.
For each position of the window, we want to compute some information. For example, we could store an ordered set of integers representing the integers inside the window. If the window currently spans the range $i \dots j$, we observe that moving the range forward to $i+1 \dots j+1$ only removes $a_i$ and adds $a_{j+1}$ to the window. We can support these two operations and query for the minimum / maximum in the set in $O(\log N)$.
<!-- To compute the sum in the range, instead of using a set, we can store a variable $s$ representing the sum. As we move the window forward, we update $s$ by subtracting $a_i$ from $s$ and adding $a_{j+1}$ to $s$.
-->
<Resources>
<Resource source="GFG" title="Window Sliding Technique" url="window-sliding-technique"> </Resource>
</Resources>
### Implementation
<IncompleteSection />
### Problems
<Problems problems={problems.constant} />
## With Two Pointers
In general, it is not required for the subarray to have constant size as long as both the left and right endpoints of the subarray only move to the right.
<Problems problems={problems.sam} />
### Solution
<Resources>
<Resource source="Medium" title="Introduction to Sliding Window Algorithms" url="https://levelup.gitconnected.com/an-introduction-to-sliding-window-algorithms-5533c4fe1cc7"> </Resource>
</Resources>
### Problems
<Problems problems={problems.general} />

View file

@ -3,7 +3,7 @@ id: springboards
title: "Max Suffix Query with Insertions Only"
author: Benjamin Qi
prerequisites:
- harder-ordered
- intro-ordered
description: "A solution to USACO Gold - Springboards."
frequency: 1
---

View file

@ -1,6 +1,6 @@
---
id: stacks-queues
title: Introduction to Stacks & Queues
id: stacks
title: Stacks
author: Darren Yao
description: "Two data structures to efficently add and remove the first and last element."
prerequisites:
@ -16,18 +16,14 @@ export const problems = {
general: [
new Problem("LC", "Max Histogram Area", "largest-rectangle-in-histogram", "Normal", false, [],""),
new Problem("Old Gold", "Concurrently Balanced Strings", "194", "Normal", false, [],""),
new Problem("YS","Persistent Queue","persistent_queue","Normal",false,["DFS"],""),
new Problem("Gold", "Modern Art 2","743", "Hard", false, [], ""),
new Problem("Gold", "Dishwashing","922", "Hard", false, [], ""),
],
};
## Additional Reading
<Resources>
<Resource source="CPH" title="4.5 - Stacks, Queues, Priority Queues"></Resource>
<Resource source="PAPS" title="3.2 to 3.4 - C++ STL"></Resource>
<Resource source="PAPS" title="6.2, 6.3, 6.5 - Stacks, Queues, Priority Queues"></Resource>
<Resource source="CPH" title="4.5 - Stacks"></Resource>
<Resource source="PAPS" title="3.3, 6.2 - Stacks"></Resource>
<Resource source="CP1" title="2.2 - Data Structures with Built-in Libraries"> </Resource>
</Resources>
@ -79,101 +75,8 @@ System.out.println(s.size()); // 2
</LanguageSection>
## Queues
A queue is a First In First Out (FIFO) data structure that supports three operations, all in $O(1)$ time.
<LanguageSection>
<CPPSection>
### [C++](http://www.cplusplus.com/reference/queue/queue/)
- `push`: insertion at the back of the queue
- `pop`: deletion from the front of the queue
- `front`: which retrieves the element at the front without removing it.
```cpp
queue<int> q;
q.push(1); // [1]
q.push(3); // [3, 1]
q.push(4); // [4, 3, 1]
q.pop(); // [4, 3]
cout << q.front() << endl; // 3
```
</CPPSection>
<JavaSection>
### Java
- `add`: insertion at the back of the queue
- `poll`: deletion from the front of the queue
- `peek`: which retrieves the element at the front without removing it
Java doesn't actually have a `Queue` class; it's only an interface. The most commonly used implementation is the `LinkedList`, declared as follows:
```java
Queue<Integer> q = new LinkedList<Integer>();
q.add(1); // [1]
q.add(3); // [3, 1]
q.add(4); // [4, 3, 1]
q.poll(); // [4, 3]
System.out.println(q.peek()); // 3
```
</JavaSection>
</LanguageSection>
## Deques
A **deque** (usually pronounced "deck") stands for double ended queue and is a combination of a stack and a queue, in that it supports $O(1)$ insertions and deletions from both the front and the back of the deque. Not very common in Bronze / Silver.
<LanguageSection>
<CPPSection>
### [C++](http://www.cplusplus.com/reference/deque/deque/)
The four methods for adding and removing are `push_back`, `pop_back`, `push_front`, and `pop_front`.
```cpp
deque<int> d;
d.push_front(3); // [3]
d.push_front(4); // [4, 3]
d.push_back(7); // [4, 3, 7]
d.pop_front(); // [3, 7]
d.push_front(1); // [1, 3, 7]
d.pop_back(); // [1, 3]
```
</CPPSection>
<JavaSection>
### Java
In Java, the deque class is called `ArrayDeque`. The four methods for adding and removing are `addFirst` , `removeFirst`, `addLast`, and `removeLast`.
```java
ArrayDeque<Integer> deque = new ArrayDeque<Integer>();
deque.addFirst(3); // [3]
deque.addFirst(4); // [4, 3]
deque.addLast(7); // [4, 3, 7]
deque.removeFirst(); // [3, 7]
deque.addFirst(1); // [1, 3, 7]
deque.removeLast(); // [1, 3]
```
</JavaSection>
</LanguageSection>
## Monotonic Stack
## Application: Nearest Smaller Element
<Problems problems={problems.nearest} />
@ -181,24 +84,22 @@ Consider the following problem:
> Given an array, $a$, of $N$ ($1 \le N \le 10^5$) integers, for every index $i$, find the rightmost index $j$ such that $j < i$ and $a_i > a_j$.
To solve this, let's store a stack of pairs of `<value, index>` and iterate over the array from left to right. For some index $i$, we will compute $ans_i$, the rightmost index for $i$, as follows:
<Resources>
<Resource source="CPH" title="8.2 - Nearest Smaller Element"></Resource>
<Resource source="Medium" title="Monotonic Stack" url="https://medium.com/@vishnuvardhan623/monotonic-stack-e9dcc4fa8c3e"></Resource>
</Resources>
To solve this, let's store a stack of pairs of `<value, index>` and iterate over the array from left to right. For some index $i$, we will compute $ans_i$, the rightmost index for $i$, as follows:
- Keep popping the top element off the stack as long as $value \ge a_i$. This is because we know that the pair containing $value$ will never be the solution to any index $j > i$, since $a_i$ is less than or equal to than $value$ and has an index further to the right.
- If $value < a_i$, set $ans[i]$ to $index$, because a stack stores the most recently added values first (or in this case, the rightmost ones), $index$ will contain the rightmost value which is less than $a_i$. Then, pop the top element off the stack, because $index$ can't be the solution for two elements.
The stack we used is called a **monotonic stack** because we keep popping off the top element of the stack which maintains it's monotonicity (the same property needed for algorithms like binary search) because the elements in the stack are increasing.
(add code)
### Implementation
<IncompleteSection />
### Further Reading
<Resources>
<Resource source="CPH" title="8.2 - Nearest Smaller Element"></Resource>
<Resource source="Medium" title="Monotonic Stack" url="https://medium.com/@vishnuvardhan623/monotonic-stack-e9dcc4fa8c3e"></Resource>
</Resources>
## Problems
<Problems problems={problems.general} />

View file

@ -3,8 +3,8 @@ id: toposort
title: "Topological Sort"
author: Benjamin Qi, Michael Cao, Nathan Chen
prerequisites:
- Gold - Breadth First Search
- Gold - Introduction to Dynamic Programming
- bfs
- intro-dp
description: "An ordering of vertices in a directed acyclic graph that ensures that a node is visited before a node it has a directed edge to."
frequency: 1
---
@ -58,7 +58,7 @@ The BFS version, known as [Kahn's Algorithm](https://en.wikipedia.org/wiki/Topol
<LanguageSection>
<CppSection>
<CPPSection>
```cpp
int in_degree[100000];
@ -89,7 +89,7 @@ void compute() {
}
```
</CppSection>
</CPPSection>
<JavaSection>
@ -152,7 +152,7 @@ Note that the implementation of this idea below uses Kahn's algorithm for topolo
<LanguageSection>
<CppSection>
<CPPSection>
```cpp
#include <bits/stdc++.h>
@ -254,7 +254,7 @@ int main() { //See "Intro - Fast I/O" for more information about the first two l
}
```
</CppSection>
</CPPSection>
<JavaSection>

View file

@ -9,11 +9,19 @@ description: "?"
frequency: 1
---
<!--
TODO:
- Add more resources
-->
import { Problem } from "../models";
export const problems = {
general: [
new Problem("CF", "Ciel the Commander", "problemset/problem/321/C", "Easy", false, ["Centroid"], ""),
new Problem("Plat", "New Barns", "817", "Normal", true, ["Centroid"], ""),
new Problem("CF", "Sherlock's bet to Moriarty", "contest/776/problem/F", "Normal", false, ["Centroid"], ""),
new Problem("CF", "Digit Tree", "contest/715/problem/C", "Normal", false, ["Centroid", "NT"], ""),
new Problem("CF", "Double Tree", "contest/1140/problem/G", "Normal", false, ["Centroid", "DP"], ""),
@ -82,9 +90,43 @@ void centroid(int n = 1)
</CPPSection>
<JavaSection />
<JavaSection>
<PySection />
<!-- Modified from above. I can't guarauntee it compiles and functions as expected -->
```java
boolean[] r = new boolean[MN];//removed
int[] s = new int[MN];//subtree size
public int dfs(int n, int p)
{
s[n] = 1;
for(int x : a[n])
if(x != p && !r[x])
s[n] += dfs(x, n);
return s[n];
}
public int get_centroid(int n, int ms, int p)//n = node, ms = size of tree, p = parent
{
for(int x : a[n])
if(x != p && !r[x])
if(s[x]*2 > ms)
return get_centroid(x, ms, n);
return n;
}
public void centroid(int n)
{
int C = get_centroid(n, dfs(n, 0), 0);
//do something
r[C] = 1;
for(int x : a[C])
if(!r[x])
centroid(x);
}
```
</JavaSection>
</LanguageSection>

View file

@ -22,6 +22,7 @@ export const problems = {
new Problem("CSES", "Elevator Rides", "1653", "Normal", false, ["Bitmasks"], ""),
new Problem("ojuz", "IZhO Bank", "IZhO14_bank", "Normal", false, ["Bitmasks"], ""),
new Problem("YS", "Max Indep Set", "maximum_independent_set", "Normal", false, ["Bitmasks", "Meet in Middle"], ""),
new Problem("CF", "Wise Men", "contest/1326/problem/F2", "Very Hard", false, ["Bitmasks", "DP", "SOS"], "Solve the case where for each binary string s, a 1 means that the adjacent men know each other, and the 0 means nothing: they can know each other or not."),
],
broken: [
new Problem("CF", "Guards in the Storehouse", "problemset/problem/845/F", "Normal", false, [], ""),
@ -42,6 +43,7 @@ You can often use this to solve subtasks.
<Resource source="CPH" title="10 (Bit Manipulation), 19.2 (Hamiltonian Paths)"> </Resource>
<Resource source="CF" title="DP Over Subsets" url="blog/entry/337"> </Resource>
<Resource source="HE" title="DP and Bit Masking" url="https://www.hackerearth.com/practice/algorithms/dynamic-programming/bit-masking/tutorial/"> </Resource>
<Resource source="CF" title="SOS Dynamic Programming" url="blog/entry/45223"> Sum over Subsets DP </Resource>
</Resources>
## Problems
@ -56,4 +58,4 @@ You can often use this to solve subtasks.
(fill in? more probs?)
<Problems problems={problems.broken} />
<Problems problems={problems.broken} />

View file

@ -202,7 +202,7 @@ Naively, this would take up $O(N^2)$ memory, but *path compression* enables it t
<Problems problems={problems.tree} />
### Generate Suffix Array
### Generate Suffix Array from Suffix Tree
A suffix array can be generated by the suffix tree by taking the dfs traversal of the suffix tree.
@ -215,12 +215,12 @@ A suffix array can be generated by the suffix tree by taking the dfs traversal o
```cpp
int N, sa[MN];//length of string, suffix array
struct edge
struct Edge
{
public:
int n, l, r;//node, edge covers s[l..r]
explicit operator bool() const {return n!=-1;}
} c[MN*2][26];
} c[MN*2][26]; // edges of a suffix tree
void dfs(int n=0, int d=0)
{
@ -237,9 +237,74 @@ void dfs(int n=0, int d=0)
```
</CPPSection>
<JavaSection />
</LanguageSection>
<PySection />
### Generate Suffix Tree from Suffix Array
Of course, the above operation can be reversed as well.
Each element in the suffix array corresponds to a leaf in the suffix tree.
The LCP array stores information about the Lowest Common Ancestor of two adjacent elements in the suffix array.
Using these two pieces of information, we can construct the suffix tree from the suffix array in linear time.
<LanguageSection>
<CPPSection>
```cpp
//untested
int N, sa[MN], lcp[MN];//length of string, suffix array, lcp array: lcp[i] stores longest common prefix of sa[i] and sa[i+1]
struct Edge
{
public:
int n, l, r; //node, edge covers s[l..r]
explicit operator bool() const {return n!=-1;}
} c[MN*2][26]; // edges of suffix tree
void build_tree()
{
}
```
</CPPSection>
</LanguageSection>
### Generate Suffix Tree from Suffix Automaton
One interesting thing about Suffix Trees and Suffix Automata is that the link tree of a Suffix Automaton is equivalent to the Suffix Tree of the reversed string.
Since Suffix Automata are much easier to create than Suffix Trees, we can use this as an alternate method to build a Suffix Tree, all in linear time too!
<LanguageSection>
<CPPSection>
<!-- https://codeforces.com/edu/course/2/lesson/2/2/practice/contest/269103/submission/85759835 - This submission contains both -->
```cpp
char s[MN]; //string
int ord[MN]; // nodes representing prefixes of the string s
int u[MN*2]; // whether the node has already been created
int l[MN*2]; // link in suffix automaton
Edge c[MN*2][27]; // edge of suffix tree (not automaton; structure of automaton is not necessary to build stree)
void build_tree()
{
s[N] = 26; // terminator
for(int i=N;i>=0;--i) ord[i]=append(ord[i+1], s[i]);
for(int i=0,x,r,l;i<=N;++i)
{
x=ord[i], r=N+1;
for(;x&&!u[x];x=l[x])
{
l=r-d[x]+d[l[x]];
c[l[x]][s[l]]={x, l, r};
r=l;
u[x]=1;
}
}
}
```
</CPPSection>
</LanguageSection>

View file

@ -58,4 +58,20 @@ export const Authors: Author[] = [
codeforces: "darren_yao",
github: "darren-yao",
},
{
photo: 'michael',
name: 'Siyong Huang',
title: 'Content Author',
blurb: '',
codeforces: "frodakcin",
github: "frodakcin",
},
{
photo: 'nathanc',
name: 'Nathan Chen',
title: 'Content Author',
blurb: '',
codeforces: "nchn27",
github: "nchn27",
},
];

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -97,18 +97,23 @@ const MODULE_ORDERING: {[key in SectionID]: Chapter[]} = {
]
},
{
name: "Binary Search",
name: "Sorting",
items: [
"binary-search-sorted",
"binary-search-ans",
"sorting-custom",
"greedy",
]
},
{
name: "Sorting",
name: "Two Pointers",
items: [
"sorting-methods",
"sorting-custom",
"greedy",
"2P",
]
},
{
name: "Binary Search",
items: [
"binary-search-ans",
]
},
{
@ -116,14 +121,6 @@ const MODULE_ORDERING: {[key in SectionID]: Chapter[]} = {
items: [
"intro-ordered",
"custom-cpp-stl",
"harder-ordered",
]
},
{
name: "Stacks & Queues",
items: [
"stacks-queues",
"sliding",
]
},
{
@ -136,6 +133,14 @@ const MODULE_ORDERING: {[key in SectionID]: Chapter[]} = {
},
],
"gold": [
{
name: "Data Structures",
items: [
"stacks",
"sliding",
"queues",
]
},
{
name: "Dynamic Programming",
items: [

View file

@ -22,9 +22,9 @@ export const IncompleteSection = ({ children }) => {
This section is not complete.
</h3>
<div className="mt-2 text-sm leading-5 text-red-700 no-bottom-margin">
{children}
Feel free to file a request to complete this using the "Contact Us"
button.
button. <br />
<i>{children}</i>
</div>
</div>
</div>

View file

@ -53,6 +53,7 @@ const sources = {
};
export const sourceTooltip = {
AoPS: 'Art of Problem Solving',
CPH: "Book - Competitive Programmer's Handbook",
PAPS: 'Book - Principles of Algorithmic Problem Solving',
IUSACO: 'Book - An Introduction to the USA Computing Olympiad',

View file

@ -319,8 +319,8 @@ export default function IndexPage(props: PageProps) {
</div>
<div className="ml-3">
<p className="text-sm leading-5 text-yellow-700 text-left">
This guide is not a syllabus. Topics on this guide reflect{' '}
<i>past</i> problems, not future problems.
This guide is not an official syllabus. Topics on this guide
reflect <i>past</i> problems, not future problems.
</p>
</div>
</div>
@ -507,15 +507,14 @@ export default function IndexPage(props: PageProps) {
<div>
<div>
<dt className="text-lg leading-6 font-medium text-gray-900">
Is this a Syllabus?
Is this an official syllabus?
</dt>
<dd className="mt-2">
<p className="text-base leading-6 text-gray-500">
<b>No. This guide is NOT a syllabus.</b> USACO does not
have an official syllabus. This guide merely lists topics
that have <i>historically</i> appeared in USACO contests;
it makes no guarantees about the topics in future USACO
contests.
<b>No, USACO does not have an official syllabus.</b>
This guide merely lists topics that have{' '}
<i>historically</i> appeared in USACO contests; it makes
no guarantees about the topics in future USACO contests.
</p>
</dd>
</div>