Merge remote-tracking branch 'refs/remotes/origin/master'

This commit is contained in:
Siyong 2020-07-19 18:00:14 -07:00
commit 91c1617467
101 changed files with 1846 additions and 1609 deletions

View file

@ -2,7 +2,7 @@
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

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

@ -9,15 +9,13 @@ prerequisites:
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
general: [
new Problem("Bronze", "Promotion Counting", "591", "Very Easy"),
new Problem("Bronze", "Word Processor", "987", "Very Easy"),
new Problem("Bronze", "Square Pasture", "663", "Very Easy"),
new Problem("Bronze", "Bucket Brigade", "939", "Very Easy"),
]
}
};
The remainder of this guide assumes that you know the basics of how to code in one of the languages listed above, including the following topics:
@ -52,7 +50,7 @@ You may find the following resources helpful for familiarizing yourself with you
The following require relatively little programming experience and no algorithmic knowledge.
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
Also check the [CSES Introductory Problems](https://cses.fi/problemset/list/) up to and including "Palindrome Reorder." Once you're done with these, you should continue onto Bronze.

View file

@ -9,21 +9,13 @@ prerequisites:
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
cses: [
new Problem("CSES", "Weird Algorithm", "1068", "Very Easy"),
],
fence: [
new Problem("Bronze", "Fence Painting", "567", "Very Easy"),
],
general: [
new Problem("Bronze", "Promotion Counting", "591", "Very Easy"),
new Problem("Bronze", "Word Processor", "987", "Very Easy"),
new Problem("Bronze", "Square Pasture", "663", "Very Easy"),
new Problem("Bronze", "Bucket Brigade", "939", "Very Easy"),
]
}
};
<Resources>
@ -38,7 +30,7 @@ export const metadata = {
In most websites (such as CodeForces and CSES), input and output are **standard**.
<Problems problems={metadata.problems.cses} />
<Problems problems={problems.cses} />
Note that this problem requires **64-bit integers**.
@ -170,7 +162,7 @@ public static void main(String[] args) {
## File I/O
<Problems problems={metadata.problems.fence} />
<Problems problems={problems.fence} />
In USACO, input is read from a file called `problemname.in`. After the program is run, output must be printed to a file called `problemname.out`. Note that you'll have to rename the `.in` and `.out` files depending on the problem. For example, in the above problem you would use `paint.in` and `paint.out`.

101
content/1_Intro/Lambda.mdx Normal file
View file

@ -0,0 +1,101 @@
---
id: lambda
title: Lambda Expressions
author: Benjamin Qi
description: "Unnamed function objects capable of capturing variables in scope."
---
<LanguageSection>
<CPPSection>
## Introduction
<Resources>
<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>
Anything more beginner-friendly?
<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
<Resources>
<Resource source="open-std" url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0200r0.html" title="Y Combinator Proposal" starred> </Resource>
<Resource source="RIP Tutorial" url="https://riptutorial.com/cplusplus/example/8508/recursive-lambdas" title="Recursive Lambdas"> </Resource>
</Resources>
If we add the following from the link above in C++14:
```cpp
namespace std {
template<class Fun>
class y_combinator_result {
Fun fun_;
public:
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 Fun>
decltype(auto) y_combinator(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
}
```
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";
import ShortenCpp from "../../additionalContent/Shorten_Cpp.mdx";
<InputOutput />
<LanguageSection>
<CPPSection>
<DebuggingCpp />
<ShortenCpp />
</CPPSection>
<JavaSection />
<PythonSection />
</LanguageSection> -->

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>`
@ -116,82 +116,4 @@ Instructions (Mac):
```
4. Run `makeSnip` from terminal. It should display a list of the templates that will be added as snippets.
5. If this succeeded, then typing `Temp` in a cpp file will automatically load my template!
## Lambda Expressions
<Resources>
<Resource
source="GFG"
url="lambda-expression-in-c"
title="Lambda Expressions in C++"
>
{' '}
</Resource>
</Resources>
(describe more)
### Recursive Lambdas
<Resources>
<Resource source="open-std" url="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0200r0.html" title="Y Combinator Proposal" starred> </Resource>
<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:
```cpp
namespace std {
template<class Fun>
class y_combinator_result {
Fun fun_;
public:
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 Fun>
decltype(auto) y_combinator(Fun &&fun) {
return y_combinator_result<std::decay_t<Fun>>(std::forward<Fun>(fun));
}
} // namespace std
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
}
```
Looks like [ecnerwal](https://codeforces.com/contest/1375/submission/86008510) uses these a lot ...
<!--
import InputOutput from "../../additionalcontent/Input_Output.mdx";
import DebuggingCpp from "../../additionalContent/Debugging_Cpp.mdx";
import ShortenCpp from "../../additionalContent/Shorten_Cpp.mdx";
<InputOutput />
<LanguageSection>
<CPPSection>
<DebuggingCpp />
<ShortenCpp />
</CPPSection>
<JavaSection />
<PythonSection />
</LanguageSection> -->
5. If this succeeded, then typing `Temp` in a cpp file will automatically load my template!

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,14 +2,13 @@
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
---
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
easier: [
new Problem("CSES", "Apple Division", "1623", "Intro|Very Easy", false, ["Recursion"], "all $2^n$ subsets"),
new Problem("Bronze", "Diamond Collector", "639", "Easy", false, ["Nested Loop"], "fix the min"), // 99.9
@ -30,7 +29,6 @@ export const metadata = {
new Problem("Bronze", "Bull in a China Shop", "640", "Very Hard", false, [], "lots of WA on this one"), // 47.38
new Problem("Silver", "Field Reduction", "642", "Very Hard", false, [], ""),
],
}
};
<Resources>
@ -115,8 +113,8 @@ A couple notes:
### Easier
<Problems problems={metadata.problems.easier} />
<Problems problems={problems.easier} />
### Harder
<Problems problems={metadata.problems.harder} />
<Problems problems={problems.harder} />

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
@ -10,8 +10,7 @@ prerequisites:
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
permSam: [
new Problem("CSES", "Creating Strings I", "1622", "Intro|Easy", false, [], "all perms of string"),
],
@ -22,10 +21,9 @@ export const metadata = {
new Problem("CSES", "Chessboard and Queens", "1624", "Normal", false, [], "Recursively backtrack. See CSES book for more details."),
new Problem("Bronze", "Livestock Lineup", "965", "Hard", false, ["permutations"], ""), // 91.95
]
}
};
<Problems problems={metadata.problems.permSam} />
<Problems problems={problems.permSam} />
<br />
@ -39,7 +37,7 @@ A **permutation** is a reordering of a list of elements. Some problems will ask
This term is mentioned quite frequently:
<Problems problems={metadata.problems.ex} />
<Problems problems={problems.ex} />
Think about how are words ordered in a dictionary. (In fact, this is where the term "lexicographical" comes from.)
@ -125,4 +123,4 @@ public class Test {
### Problems
<Problems problems={metadata.problems.perm} />
<Problems problems={problems.perm} />

View file

@ -2,25 +2,26 @@
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
---
import { Problem } from "../models";
export const metadata = {
problems: {
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("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,20 +280,29 @@ for(auto element : v) {
## Sorting
<Problems problems={metadata.problems.bubble} />
<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>
@ -322,4 +332,4 @@ Two ways to avoid this:
## Problems
<Problems problems={metadata.problems.easy} />
<Problems problems={problems.easy} />

View file

@ -8,8 +8,7 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
general: [
new Problem("Silver", "Grass Planting", "894", "Normal", false, ["tree"]),
new Problem("Bronze", "The Great Revegetation", "916", "Hard", false, []),
@ -19,7 +18,6 @@ export const metadata = {
new Problem("Bronze", "Swapity Swap", "1013", "Hard", false, ["permutation"], "Hint: One option is to keep swapping until the permutation returns to its original state (but can you do better?)."),
new Problem("Bronze", "Cow Evolution", "941", "Hard", false, [], ""),
]
}
};
Graphs can be used to represent many things, from images to wireless signals, but one of the simplest analogies is to a map. Consider a map with several cities and bidirectional roads connecting the cities. Some problems relating to graphs are:
@ -45,4 +43,4 @@ Both of these tasks will be covered in higher divisions. For now, it suffices to
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -2,14 +2,13 @@
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
---
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
tutorial: [
new Problem("Bronze", "Mad Scientist", "1012", "Normal", false, [], ""),
],
@ -17,7 +16,6 @@ export const metadata = {
new Problem("Bronze", "Cow Tipping", "689", "Hard", false, [], "Cells in the last row and column can be toggled uniquely. Toggle the appropriate ones and then recurse to the rectangle in the previous row/column, and solve the same way."),
new Problem("Bronze", "Race", "989", "Very Hard", false, [], "Greedily increment/decrement Bessies speed to fit the conditions until her total distance exceeds K."),
],
}
};
## Ad Hoc
@ -141,7 +139,7 @@ If we use greedy based on highest value first, we choose item A and then we are
Try to come up with a greedy algorithm for the USACO Bronze problem "Mad Scientist."
<Problems problems={metadata.problems.tutorial} />
<Problems problems={problems.tutorial} />
<Spoiler title="Correct Greedy Algorithm">
@ -165,7 +163,7 @@ Sometimes, if the algorithm is easy enough to implement, you don't even need to
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
<IncompleteSection>

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

@ -7,17 +7,15 @@ frequency: 2
---
import { Problem } from "../models";
export const metadata = {
problems: {
blocked: [
new Problem("Bronze", "Blocked Billboard", "759", "Easy", false, ["rect"]),
],
general: [
new Problem("Bronze", "Square Pasture", "663", "Very Easy", false, ["rect"]),
new Problem("Bronze", "Blocked Billboard II", "783", "Easy", false, ["rect"]),
new Problem("CF", "Div. 3 C - White Sheet", "contest/1216/problem/C", "Normal", false, ["rect"],"See this code (TODO; codeforces is down) for a nice implementation using the Java Rectangle class."),
]
}
export const problems = {
blocked: [
new Problem("Bronze", "Blocked Billboard", "759", "Easy", false, ["rect"]),
],
general: [
new Problem("Bronze", "Square Pasture", "663", "Very Easy", false, ["rect"]),
new Problem("Bronze", "Blocked Billboard II", "783", "Easy", false, ["rect"]),
new Problem("CF", "Div. 3 C - White Sheet", "contest/1216/problem/C", "Normal", false, ["rect"],"See this code (TODO; codeforces is down) for a nice implementation using the Java Rectangle class."),
]
};
<Resources>
@ -30,7 +28,7 @@ Most only include two or three squares or rectangles, in which case you can simp
## Example: Blocked Billboard
<Problems problems={metadata.problems.blocked} />
<Problems problems={problems.blocked} />
### Naive Solution
@ -212,4 +210,4 @@ int main(){
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -8,8 +8,7 @@ frequency: 4
import { Problem } from "../models"
export const metadata = {
problems: {
export const problems = {
easier: [
new Problem("Bronze", "Shell Game", "891", "Easy", false, ["Nested Loop"]), // 99.93
new Problem("Bronze", "Mixing Milk", "855", "Easy", false, ["Single Loop"], "just pour 100 times"), // 99.87
@ -26,7 +25,6 @@ export const metadata = {
new Problem("Bronze", "Milk Measurement", "761", "Hard"), // 95.97
new Problem("Bronze", "Angry Cows", "592", "Hard", false, [], ""), // 94.15
]
}
};
<Resources>
@ -186,8 +184,8 @@ pw.close(); // flush the output
### Easier
<Problems problems={metadata.problems.easier} />
<Problems problems={problems.easier} />
### Harder
<Problems problems={metadata.problems.harder} />
<Problems problems={problems.harder} />

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
@ -10,8 +10,7 @@ prerequisites:
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
dis: [
new Problem("CSES", "Distinct Numbers", "1621", "Easy", false, [], "Store every number in a set and print the size."),
],
@ -23,7 +22,6 @@ export const metadata = {
new Problem("Bronze", "Where Am I?", "964", "Easy", false, [], "Store all substrings in a map of <string, count>, and then find the longest length such that no substring of that length appears twice."),
new Problem("Silver", "Cities & States", "667", "Hard", false, [], "Store two maps of counts for the first two letters of a city and state code, then iterate over the cities and use the maps to efficently query for the corresponding counts."),
],
}
};
<Resources>
@ -46,7 +44,7 @@ Both Java and C++ contain two versions of sets and maps; one in which the keys a
## Sets
<Problems problems={metadata.problems.dis} />
<Problems problems={problems.dis} />
<LanguageSection>
@ -105,7 +103,7 @@ for(int element : set){
## Maps
<Problems problems={metadata.problems.ex} />
<Problems problems={problems.ex} />
<LanguageSection>
@ -149,6 +147,8 @@ System.out.println(map.containsKey(1)); // true
### Custom Hashing
There is no built in method for hashing pairs or vectors. Namely, `unordered_set<vector<int>>` does not work. In this case, we can use an [ordered map](../silver/intro-ordered) (which supports all of the functions used in the code above) or declare our own hash function.
<LanguageSection>
<CPPSection>
@ -197,7 +197,7 @@ int main() {
}
```
However, this hash function is quite bad; if we insert $(0,0), (1,1), (2,2) \ldots$ then they will all be mapped to the same bucket.
However, this hash function is quite bad; if we insert $(0,0), (1,1), (2,2) \ldots$ then they will all be mapped to the same bucket (so it would easily be **hacked**).
</CPPSection>
@ -232,9 +232,11 @@ Essentially use `unordered_map<int, int, custom_hash>` defined in the blog above
```cpp
struct chash { /// use most bits rather than just the lowest ones
const uint64_t C = ll(2e18*PI)+71; // large odd number
const int RANDOM = rng();
ll operator()(ll x) const { /// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
return __builtin_bswap64((x^RANDOM)*C); }
const int RANDOM = rng(); // random 32-bit number
ll operator()(ll x) const {
// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
return __builtin_bswap64((x^RANDOM)*C);
}
};
template<class K,class V> using um = unordered_map<K,V,chash>;
```
@ -247,8 +249,8 @@ template<class K,class V> using um = unordered_map<K,V,chash>;
### `gp_hash_table`
Mentioned in several of the links above. See Gold for dtails.
Mentioned in several of the links above. See [Gold](../gold/faster-hashmap) for details.
## Problems
<Problems problems={metadata.problems.standard} />
<Problems problems={problems.standard} />

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

@ -0,0 +1,39 @@
---
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("Silver", "Sleepy Cow Herding", "918", "Normal", false, ["2P", "Sorting"], ""),
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, []),
],
};
<Problems problems={problems.sample} />
<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

@ -10,8 +10,7 @@ frequency: 3
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
ex: [
new Problem("CF", "Div 2 C - Maximum Median", "contest/1201/problem/C", "Easy", false, [], ""),
],
@ -35,7 +34,6 @@ export const metadata = {
new Problem("CF", "Level Generation", "problemset/problem/818/F", "Hard", false, [], "first find out which is the best way to construct the graph, then it's possible to see that the number of edges increase for some range and then decrease; so, using binary search find the last i such that f(i-1)<=f(i)"),
new Problem("CF", "Packmen", "contest/847/problem/E", "Hard", false, [], "binary search on time and check if packmen can eat all keeping left and right endpoints"),
],
}
};
<Resources>
@ -154,7 +152,7 @@ static long search(){
## Example: Maximum Median
<Problems problems={metadata.problems.ex} />
<Problems problems={problems.ex} />
**Statement:** Given an array $\texttt{arr}$ of $n$ integers, where $n$ is odd, we can perform the following operation on it $k$ times: take any element of the array and increase it by $1$. We want to make the median of the array as large as possible after $k$ operations.
@ -261,8 +259,8 @@ static boolean check(long x){
## USACO Problems
<Problems problems={metadata.problems.usaco} />
<Problems problems={problems.usaco} />
## General Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -10,8 +10,7 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
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("Silver", "Out of Sorts", "834", "Very Hard", false, []),
@ -19,7 +18,6 @@ export const metadata = {
count: [
new Problem("Silver", "Counting Haybales", "666", "Normal", false, []),
],
}
};
Suppose that we want to find an element in a sorted array of size $N$ in $O(\log N)$ time. We can do this with [**binary search**](https://en.wikipedia.org/wiki/Binary_search_algorithm); each iteration of the binary search cuts the search space in half, so the algorithm tests $O(\log N)$ values. This is efficient and much better than testing every element in an array.
@ -60,7 +58,7 @@ Suppose that we want to find an element in a sorted array of size $N$ in $O(\log
A related topic is **coordinate compression**, which takes some points and reassigns them to remove wasted space.
<Problems problems={metadata.problems.count} />
<Problems problems={problems.count} />
> Farmer John has just arranged his $N$ haybales $(1\le N \le 100,000)$ at various points along the one-dimensional road running across his farm. To make sure they are spaced out appropriately, please help him answer $Q$ queries ($1 \le Q \le 100,000$), each asking for the number of haybales within a specific interval along the road.

View file

@ -5,12 +5,14 @@ author: Siyong Huang, Benjamin Qi
prerequisites:
- sorting-custom
- intro-ordered
- lambda
description: "More ways to write custom comparators in C++ and incorporating them into STL objects."
frequency: 1
---
<Resources>
<Resource source="fushar" title="Comparison Functions in C++" starred url="http://fusharblog.com/3-ways-to-define-comparison-functions-in-cpp/">Covers all of this material.</Resource>
<Resource source="CPP" url="https://en.cppreference.com/w/cpp/container/set" title="Set">reference</Resource>
</Resources>
<br />
@ -45,6 +47,12 @@ int main() {
## Comparator
<Resources>
<Resource source="SO" title="Using custom std::set comparator" url="https://stackoverflow.com/questions/2620862/using-custom-stdset-comparator"> </Resource>
</Resources>
### With a Function
```cpp
#include <bits/stdc++.h>
using namespace std;
@ -66,20 +74,14 @@ int main() {
}
```
<Info title="Pro Tip" >
You can also use the following syntax to declare set `v` using a function:
You can also use the following syntax to declare set `v` using a function
`set<Edge,decltype(&cmp)> v(cmp);`
`set<Edge,decltype(*cmp)> v(cmp);`
</Info>
Lambda expressions also work:
### With Lambda Expressions
```cpp
auto cmp = [](const Edge& x, const Edge& y) { return x.w < y.w; };
//The real type of cmp is function<bool(const Edge&, const Edge&)>
//auto is used for short
int main() {
int M = 4;
@ -92,13 +94,11 @@ int main() {
}
```
<Info title="Pro Tip" >
You can also use the following syntax to declare set `v` using a lambda
You can also use the following syntax to declare set `v` using a lambda:
`set<Edge,decltype(cmp)> v(cmp);`
</Info>
though `decltype(cmp)` is **not** actually equivalent to `bool(*)(const Edge&,const Edge&)`.
## Functors
@ -191,15 +191,4 @@ map<int,string,greater<int>> b;
priority_queue<int,vector<int>,greater<int>> c;
```
<Warning title="Priority Queues">
In C++, priority queues are sorted in decreasing order.
Specifically, larger elements have higher 'priority' and are popped first.
If you want smaller elements to be at the front of the queue, two ways are listed below
1. Overload the (`<`) operator to output the opposite effect.
2. Overload the (`>`) operator properly and use the (`greater<T>`) functor.
</Warning>
Using a custom comparator for priority queues is especially common. Again, a C++ priority queue will pop its largest element by default, while the above code will cause one to pop its smallest element instead.

View file

@ -4,14 +4,13 @@ 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
---
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CSES", "Building Roads", "1666", "Intro|Easy", false, ["DFS"]),
],
@ -49,7 +48,6 @@ export const metadata = {
new Problem("Silver", "The Great Revegetation", "920", "Easy", false, ["Bipartite"]),
new Problem("Silver", "Clock Tree", "1016", "Hard", false, []),
],
}
};
## Resources
@ -66,7 +64,7 @@ export const metadata = {
## Counting Connected Components
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
### Implementation
@ -128,7 +126,7 @@ public static int count_components()
### Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
## Tree Problems
@ -192,14 +190,14 @@ public static void dfs(int node)
### Problems
<Problems problems={metadata.problems.tree} />
<Problems problems={problems.tree} />
## Graph Two-Coloring
*Graph two-coloring* refers to assigning a boolean value to each node of the graph, dictated by the edge configuration.
The most common example of a two-colored graph is a *bipartite graph*, in which each edge connects two nodes of opposite colors.
<Problems problems={metadata.problems.bipsample} />
<Problems problems={problems.bipsample} />
### Resources
@ -268,4 +266,4 @@ public static void dfs(int node)
### Problems
<Problems problems={metadata.problems.bip} />
<Problems problems={problems.bip} />

View file

@ -10,8 +10,7 @@ frequency: 3
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("LC", "Flood Fill", "https://leetcode.com/problems/flood-fill/", "Intro|Easy", false, []),
new Problem("CSES", "Counting Rooms", "1192", "Easy", false, []),
@ -29,10 +28,9 @@ export const metadata = {
new Problem("Silver", "Snow Boots", "811", "Hard", false, []),
new Problem("Silver", "Mooyo Mooyo", "860", "Hard", false, []),
],
}
};
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
<br />
@ -208,4 +206,4 @@ static void floodfill(int r, int c, int color){
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -4,15 +4,14 @@ 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
---
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CF", "Div 2 B - Badge", "contest/1020/problem/B", "Very Easy", false, ["Func Graph"], "Try to solve the problem in $O(N)$!"),
],
@ -26,14 +25,13 @@ export const metadata = {
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."),
],
}
};
## Functional Graphs
We'll consider graphs like the one presented in this problem:
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
< br/>
@ -122,4 +120,4 @@ pair<int, int> detect_cycle(int *next, int start_node) //return pair(length of c
### Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -12,8 +12,7 @@ frequency: 3
import {Problem} from "../models"
export const metadata = {
problems: {
export const problems = {
movie: [
new Problem("CSES", "Movie Festival", "1629", "Easy", false, [], ""),
],
@ -42,7 +41,6 @@ export const metadata = {
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"),
]
}
};
<Resources>
@ -64,7 +62,7 @@ Here, we'll focus on problems where some sorting step is involved.
## Example: The Scheduling Problem
<Problems problems={metadata.problems.movie} />
<Problems problems={problems.movie} />
There are $N$ events, each described by their starting and ending times. You can only attend one event at a time, and if you choose to attend an event, you must attend the entire event. Traveling between events is instantaneous. What's the maximum number of events you can attend?
@ -177,12 +175,12 @@ pw.close();
## CSES Problems
<Problems problems={metadata.problems.cses} />
<Problems problems={problems.cses} />
## USACO Problems
<Problems problems={metadata.problems.usaco} />
<Problems problems={problems.usaco} />
## Other Problems
<Problems problems={metadata.problems.other} />
<Problems problems={problems.other} />

View file

@ -4,129 +4,12 @@ title: "Harder Problems with Ordered Sets"
author: Benjamin Qi
prerequisites:
- custom-cpp-stl
- stacks-queues
description: "More advanced uses of ordered sets with example problems."
frequency: 2
---
import { Problem } from "../models";
export const metadata = {
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)"),
]
}
export const problems = {
};
## Example: Using Iterators
<Problems problems={metadata.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={metadata.problems.general} />

View file

@ -3,20 +3,29 @@ id: intro-ordered
title: "Introduction to Ordered Sets"
author: Darren Yao, Benjamin Qi
prerequisites:
- Bronze - Unordered Maps & Sets
description: "A data structure that supports quick insertion and deletion by maintaining keys in sorted order."
- unordered
description: "Data structures that maintain keys in sorted order."
frequency: 2
---
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
standard: [
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)"),
]
};
<Resources>
@ -129,7 +138,7 @@ System.out.println(map.lowerKey(3)); // ERROR
## Multisets
Lastly, there is the **multiset**, which is essentially a sorted set that allows multiple copies of the same element.
A **multiset** is a sorted set that allows multiple copies of the same element.
<LanguageSection>
@ -189,6 +198,54 @@ static void remove(int x){
</LanguageSection>
## 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).
<LanguageSection>
<CPPSection>
### [C++](http://www.cplusplus.com/reference/queue/priority_queue/)
```cpp
priority_queue<int> pq;
pq.push(7); // [7]
pq.push(2); // [2, 7]
pq.push(1); // [1, 2, 7]
pq.push(5); // [1, 2, 5, 7]
cout << pq.top() << endl; // 7
pq.pop(); // [1, 2, 5]
pq.pop(); // [1, 2]
pq.push(6); // [1, 2, 6]
```
</CPPSection>
<JavaSection>
### Java
In Java, we delete and retrieve the element of **lowest** rather than highest priority.
```java
PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
pq.add(7); // [7]
pq.add(2); // [7, 2]
pq.add(1); // [7, 2, 1]
pq.add(5); // [7, 5, 2, 1]
System.out.println(pq.peek()); // 1
pq.poll(); // [7, 5, 2]
pq.poll(); // [7, 5]
pq.add(6); // [7, 6, 5]
```
</JavaSection>
</LanguageSection>
## Using Iterators
@ -198,18 +255,116 @@ static void remove(int x){
next(), prev(), ++, --
</CPPSection>
<JavaSection>
</JavaSection>
</LanguageSection>
<IncompleteSection />
## Standard
## Easy
<Problems problems={metadata.problems.standard} />
<Problems problems={problems.standard} />
## 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

@ -10,8 +10,7 @@ frequency: 3
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("YS", "Static Range Sum", "static_range_sum", "Easy", false, [], "equivalent to [CSES Range Sum Queries I](https://cses.fi/problemset/task/1646)"),
],
@ -47,7 +46,6 @@ export const metadata = {
new Problem("Google KickStart", "Candies (Test Set 1)", "https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ff43/0000000000337b4d", "Easy", false, ["Prefix Sums"], ""),
new Problem("AC", "Multiple of 2019", "https://atcoder.jp/contests/abc164/tasks/abc164_d", "Hard", false, ["Prefix Sums"], "Make use of the fact that adding 0's to the end of a number does not affect whether it is a multiple of 2019 (because 10 and 2019 are coprime)."),
],
}
};
@ -59,7 +57,7 @@ export const metadata = {
## Introduction
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
Let's say we have a one-indexed integer array $\texttt{arr}$ of size $N$ and we want to compute the value of
$$
@ -206,13 +204,13 @@ These are also known as [partial sums](https://mathworld.wolfram.com/PartialSum.
### Problems
<Problems problems={metadata.problems.cum} />
<Problems problems={problems.cum} />
## Max Subarray Sum
Now we'll look at some extensions.
<Problems problems={metadata.problems.maxsum} />
<Problems problems={problems.maxsum} />
This problem has a solution known as [Kadane's Algorithm](https://en.wikipedia.org/wiki/Maximum_subarray_problem#Kadane's_algorithm). Please don't use that solution; try to solve it with prefix sums.
@ -226,11 +224,11 @@ Consider the desired maximum subarray. As you go along from left to right, the p
Similar to prefix sums, you can also take prefix minimum or maximum; but *you cannot* answer min queries over an arbitrary range with prefix minimum. (This is because minimum doesn't have an inverse operation, the way subtraction is to addition.) On the other hand, XOR is its own inverse operation, meaning that the XOR of any number with itself is zero.
<Problems problems={metadata.problems.related} />
<Problems problems={problems.related} />
## 2D Prefix Sums
<Problems problems={metadata.problems.sample2} />
<Problems problems={problems.sample2} />
Now, what if we wanted to process $Q$ queries for the sum over a subrectangle of a $N$ rows by $M$ columns matrix in two dimensions? Let's assume both rows and columns are 1-indexed, and we use the following matrix as an example:
@ -475,7 +473,7 @@ as expected.
Since no matter the size of the submatrix we are summing, we only need to access four values of the 2D prefix sum array, this runs in $O(1)$ per query after an $O(NM)$ preprocessing.
<Problems problems={metadata.problems.cum2} />
<Problems problems={problems.cum2} />
## More Complex Applications
@ -508,4 +506,4 @@ $$
Which is what we were looking for!
<Problems problems={metadata.problems.complex} />
<Problems problems={problems.complex} />

View file

@ -1,91 +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 metadata = {
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={metadata.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={metadata.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={metadata.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={metadata.problems.qs} />

View file

@ -214,4 +214,4 @@ Comments: Comparator 1 sorts array $a$ in decreasing order. Comparator 2 sorts a
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -5,13 +5,13 @@ frequency: 3
author: Darren Yao, Siyong Huang, Michael Cao, Benjamin Qi
prerequisites:
- pairs-tuples
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."
- lambda
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";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("Silver", "Wormhole Sort", "992", "Normal", false, [], ""),
],
@ -25,7 +25,6 @@ export const metadata = {
new Problem("Silver", "Triangles", "1015", "Hard", false, [], ""),
new Problem("Silver", "Meetings", "967", "Very Hard", false, [], ""),
],
}
};
<Resources>
@ -36,7 +35,7 @@ export const metadata = {
## Example: Wormhole Sort
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
There are multiple ways to solve this problem. We won't discuss the full solution here, but all of them start by sorting the edges in nondecreasing order of weight. For example, the sample contains the following edges:
@ -279,7 +278,7 @@ int main() {
```
We can also use [lambda expressions](https://www.geeksforgeeks.org/lambda-expression-in-c/) in C++11 or above.
We can also use lambda expressions in C++11 or above:
```cpp
sort(begin(v),end(v),[](const Edge& x, const Edge& y) { return x.w < y.w; });
@ -573,4 +572,4 @@ public class Sol {
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -10,12 +10,10 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
bubble: [
new Problem("Silver", "Out of Sorts", "834", "Very Hard", false, []),
],
}
};
<Resources>
@ -32,7 +30,7 @@ There are many sorting algorithms, here are some sources to learn about the popu
## Bubble Sort
<Problems problems={metadata.problems.bubble} />
<Problems problems={problems.bubble} />
### Tutorial

View file

@ -10,8 +10,7 @@ description: "Both Java and C++ have built-in functions for sorting. However, if
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("Silver", "Wormhole Sort", "992", "Normal", false, [], ""),
],
@ -23,12 +22,11 @@ export const metadata = {
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("Silver", "Meetings", "967", "Very Hard", false, [], ""),
],
}
};
## Example: Wormhole Sort
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
There are multiple ways to solve this problem. We won't discuss the full solution here, but all of them start by sorting the edges in nondecreasing order of weight.

View file

@ -1,270 +0,0 @@
---
id: stacks-queues
title: Introduction to Stacks & Queues
author: Darren Yao
description: "Two data structures to efficently add and remove the first and last element."
prerequisites:
- intro-ds
---
import { Problem } from "../models";
export const metadata = {
problems: {
nearest: [
new Problem("CSES", "Nearest Smaller Values", "1645", "Easy", false, [], ""),
],
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="CP1" title="2.2 - Data Structures with Built-in Libraries"> </Resource>
</Resources>
## Stacks
A stack is a **Last In First Out** (LIFO) data structure that supports three operations, all in $O(1)$ time. Think of it like a real-world stack of papers (or cards).
<LanguageSection>
<CPPSection>
### [C++](http://www.cplusplus.com/reference/stack/stack/)
- `push`: adds an element to the top of the stack
- `pop`: removes an element from the top of the stack
- `top`: retrieves the element at the top without removing it
```cpp
stack<int> s;
s.push(1); // [1]
s.push(13); // [1, 13]
s.push(7); // [1, 13, 7]
cout << s.top() << endl; // 7
s.pop(); // [1, 13]
cout << s.size() << endl; // 2
```
</CPPSection>
<JavaSection>
### Java
- `push`: adds an element to the top of the stack
- `pop`: removes an element from the top of the stack
- `peek`: retrieves the element at the top without removing it
```java
Stack<Integer> s = new Stack<Integer>();
s.push(1); // [1]
s.push(13); // [1, 13]
s.push(7); // [1, 13, 7]
System.out.println(s.peek()); // 7
s.pop(); // [1, 13]
System.out.println(s.size()); // 2
```
</JavaSection>
</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>
## Priority Queues
<LanguageSection>
<CPPSection>
### [C++](http://www.cplusplus.com/reference/queue/priority_queue/)
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. Priority is based on a comparator function. The priority queue is one of the most important data structures in competitive programming, so make sure you understand how and when to use it.
```cpp
priority_queue<int> pq;
pq.push(7); // [7]
pq.push(2); // [2, 7]
pq.push(1); // [1, 2, 7]
pq.push(5); // [1, 2, 5, 7]
cout << pq.top() << endl; // 7
pq.pop(); // [1, 2, 5]
pq.pop(); // [1, 2]
pq.push(6); // [1, 2, 6]
```
</CPPSection>
<JavaSection>
### Java
In Java, we delete and retrieve the element of **lowest** priority.
```java
PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
pq.add(7); // [7]
pq.add(2); // [7, 2]
pq.add(1); // [7, 2, 1]
pq.add(5); // [7, 5, 2, 1]
System.out.println(pq.peek()); // 1
pq.poll(); // [7, 5, 2]
pq.poll(); // [7, 5]
pq.add(6); // [7, 6, 5]
```
</JavaSection>
</LanguageSection>
## Monotonic Stack
<Problems problems={metadata.problems.nearest} />
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:
- 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)
<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={metadata.problems.general} />
<!--
(actually go through these and check ...)
### Stack
- UVa 00514 - Rails
- UVa 00732 - Anagram by Stack
- UVa 01062 - Containers
### Queue / Deque
- UVa 10172 - The Lonesome Cargo
- UVa 10901 - Ferry Loading III
- UVa 11034 - Ferry Loading IV
-->

View file

@ -10,8 +10,7 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CSES", "Message Route", "1667", "Easy", false, ["BFS"]),
],
@ -25,10 +24,9 @@ export const metadata = {
example: [
new Problem("Gold", "Cow Navigation", "695", "Normal", false, ["BFS"]),
]
}
};
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
## Resources
@ -181,7 +179,7 @@ class Main {
In the gold division, the problem statement will never directly be, "Given an unweighted graph, find the shortest path between node $u$ and $v$." Instead, the difficulty in many BFS problems are modifying the problem into a graph on which we can run BFS and get the answer.
<Problems problems={metadata.problems.example} />
<Problems problems={problems.example} />
In this problem, Bessie stands on a grid and wants to go from the lower left corner to upper-right corner in as few moves as possible. An initial idea could be to model the grid as a graph, where adjacent cells are connected by edges, and run a BFS to find the shortest path.
@ -212,4 +210,4 @@ Don't forget that once Bessie reaches the goal, she will ignore further commands
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -10,8 +10,7 @@ frequency: 0
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
und: [
new Problem("CSES", "Round Trip", "1669", "Easy", false, ["Cycle"]),
],
@ -21,7 +20,6 @@ export const metadata = {
general: [
new Problem("CSES", "Graph Girth", "1707", "Easy", false, ["Cycle"]),
],
}
};
@ -29,7 +27,7 @@ export const metadata = {
## Undirected Graphs
<Problems problems={metadata.problems.und} />
<Problems problems={problems.und} />
(explanation?)
@ -41,7 +39,7 @@ An algorithm known as **BFS-Cycle** returns an integer that is at most one more
## Directed Graphs
<Problems problems={metadata.problems.dir} />
<Problems problems={problems.dir} />
The same general idea is implemented below to find any cycle in a directed graph (if one exists). Note that this is almost identical to the DFS algorithm for topological sorting.
@ -107,6 +105,6 @@ int main()
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
VT-HSPC 2019?

View file

@ -11,8 +11,7 @@ frequency: 4
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
usacoEasy: [
new Problem("Gold", "Hoof Paper Scissors", "694", "Easy", false, ["DP"], "dp[first i games][# changes][last gesture] -> max games won"),
new Problem("Gold", "Time is Mooney", "993", "Easy", true, ["DP", "Graphs"], "dp[time][city] -> money"),
@ -50,7 +49,6 @@ export const metadata = {
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"),
],
}
}
Dynamic Programming is an important algorithmic technique in competitive programming that appears at all levels of competition.
@ -83,31 +81,31 @@ Sometimes it's a good idea to write a slower polynomial-time solution and then o
These are easier USACO problems which use DP, and don't require many optimizations or complex states.
<Problems problems={metadata.problems.usacoEasy} />
<Problems problems={problems.usacoEasy} />
## Knapsack
Common variations on Knapsack, followed by more challenging problems which feature variations on the state and additional algorithms.
<Problems problems={metadata.problems.knapsack} />
<Problems problems={problems.knapsack} />
## Paths in a Grid (and related)
Interesting applications of "number of paths on a grid," some of which don't directly present a grid in the problem, but can be modelled as one. <Asterisk> Such as Longest Common Subsequence. </Asterisk>
<Problems problems={metadata.problems.pathsGrid} />
<Problems problems={problems.pathsGrid} />
## Longest Increasing Subsequence
Some of the problems in this section don't initially look like Longest Increasing Subsequence, but it ends up being the solution. <Asterisk>This can happen a lot, which is why it's a good idea to not focus on one topic unless you have a full solution</Asterisk>
<Problems problems={metadata.problems.lis} />
<Problems problems={problems.lis} />
## Harder USACO Problems
Finish with some more challenging Dynamic Programming problems! Some of these can be very difficult, so skip around if you want.
<Problems problems={metadata.problems.usacoPast} />
<Problems problems={problems.usacoPast} />
## Other DP Problemsets

View file

@ -10,8 +10,7 @@ frequency: 2
---
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CSES", "Tree Matching", "1130", "Easy", false, ["DP"], ""),
],
@ -29,10 +28,9 @@ export const metadata = {
new Problem("CSES", "Creating Offices", "1752", "Hard", false, ["Greedy"], "equivalent to BOI - Cat in a Tree"),
new Problem("Plat", "Cow At Large", "793", "Hard", false, [], "This is not too hard to fakesolve. First write an (optimized?) O(N^2) DP to pass test cases 1-6. This won't work for test cases 7-11, but in these test cases all trees have at most 20 leaves. Therefore it suffices to compress tree edges (repeatedly remove vertices of degree 2) and run the same solution. For a legit DP solution, see Eric Zhang's comment here: https://codeforces.com/blog/entry/57170?#comment-410179"),
],
}
}
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
## Tutorial
@ -45,7 +43,7 @@ export const metadata = {
## Solving for All Roots
<Problems problems={metadata.problems.allRoots} />
<Problems problems={problems.allRoots} />
(dfs twice)
@ -99,7 +97,6 @@ template<int SZ> struct SubtreeDP {
T p = T(); trav(t,adj[i]) p += getSub(t,i);
ps(p.v);
}
}
};
int main() {
@ -132,7 +129,7 @@ Don't just dive into trying to figure out a DP state and transitions -- make som
</Info>
<Problems problems={metadata.problems.usaco} />
<Problems problems={problems.usaco} />
<Spoiler title="Ostap & Tree">

View file

@ -10,8 +10,7 @@ frequency: 3
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("YS", "Union Find", "unionfind", "Intro|Easy", false, []),
],
@ -20,10 +19,9 @@ export const metadata = {
new Problem("Gold", "Mootube", "789", "Normal", false, [], "Answer queries in decreasing order of $k$. Maintain size of each connected component. Same as [CSES Road Construction](https://cses.fi/problemset/task/1676)"),
new Problem("Gold", "Favorite Colors", "1042", "Very Hard", false, ["DSU"], "Small to large merging is mentioned in the editorial, but we were unable to break solutions that just merged naively. Alternatively, just merge linked lists in $O(1)$ time."),
],
}
};
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
## Resources
@ -102,4 +100,4 @@ boolean merge(int a, int b) {
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -10,12 +10,13 @@ prerequisites:
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
three: [
new Problem("Gold", "3SUM", "994", "Normal", false, [], ""),
],
}
four: [
new Problem("CSES", "Sum of Four Values", "1642", "Normal", false, [], ""),
],
};
<Resources>
@ -97,7 +98,7 @@ then the actual size of `g` is always at least `1<<16` (regardless of calls to `
### Solving ThreeSum
<Problems problems={metadata.problems.three} />
<Problems problems={problems.three} />
You're supposed to use array since values are small :|
@ -106,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);
}
@ -120,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

@ -11,8 +11,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CF", "VK Cup Wildcard R1 C - Prime Factorization", "problemset/problem/162/C", "Intro|Very Easy", false, []),
],
@ -25,7 +24,6 @@ export const metadata = {
new Problem("Gold", "Cow Poetry", "897", "Normal", false, ["Knapsack", "Exponentiation"], "First consider the case where there are only two lines with the same class."),
new Problem("Gold", "Exercise", "1043", "Normal", false, ["Knapsack", "Prime Factorization"], "Prime factorize $K$."),
],
}
};
<Resources>
@ -39,7 +37,7 @@ export const metadata = {
## Prime Factorization
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
A number $a$ is called a **divisor** or a **factor** of a number $b$ if $b$ is divisible by $a$, which means that there exists some integer $k$ such that $b = ka$. Conventionally, $1$ and $n$ are considered divisors of $n$. A number $n > 1$ is **prime** if its only divisors are $1$ and $n$. Numbers greater than \(1\) that are not prime are **composite**.
@ -226,4 +224,4 @@ See the module in the [Advanced](../adv/extend-euclid) section.
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -11,8 +11,7 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
standard: [
new Problem("Kattis", "MST", "minspantree", "Easy", false, ["MST"], ""),
new Problem("CSES", "Road Reparation", "1675", "Easy", false, ["MST"], ""),
@ -24,10 +23,9 @@ export const metadata = {
new Problem("HR", "Spanning Tree Fraction", "https://www.hackerrank.com/contests/w31/challenges/spanning-tree-fraction/problem", "Normal", false, ["MST", "Binary Search"], ""),
new Problem("Plat", "Fencedin", "625", "Hard", false, ["Kruskal"], ""),
],
}
};
<Problems problems={metadata.problems.standard} />
<Problems problems={problems.standard} />
## Resources
@ -48,4 +46,4 @@ export const metadata = {
## USACO Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -10,8 +10,7 @@ frequency: 3
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
seg: [
new Problem("CSES", "Range Minimum Queries II", "1649", "Intro|Easy", false, ["PURQ"], ""),
new Problem("YS", "Point Set Range Composite", "point_set_range_composite", "Easy", false, ["PURQ"], "Order of operations matters!"),
@ -44,10 +43,9 @@ export const metadata = {
new Problem("Old Gold", "Cow Hopscotch", "532", "Hard", false, [], ""),
new Problem("Plat", "Out of Sorts", "840", "Hard", false, [], ""),
],
}
};
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
<br />
@ -60,7 +58,7 @@ Both **segment trees** and **binary indexed trees** can accomplish this.
## Segment Tree
<Problems problems={metadata.problems.seg} />
<Problems problems={problems.seg} />
A **segment tree** allows you to do point update and range query in $O(\log N)$ time each for **any** associative operation, not just summation.
@ -106,7 +104,6 @@ template<class T> struct Seg { // comb(ID,b) = b
if (r&1) rb = comb(seg[--r],rb);
}
return comb(ra,rb);
}
};
```
@ -208,10 +205,10 @@ Covered in [platinum](../plat/seg-ext).
## Practice Problems
<Problems problems={metadata.problems.practice} />
<Problems problems={problems.practice} />
## USACO Problems
Haircut, Balanced Photo, and Circle Cross are just variations on inversion counting.
<Problems problems={metadata.problems.usaco} />
<Problems problems={problems.usaco} />

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

@ -0,0 +1,126 @@
---
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, [], ""),
],
};
## 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>
## 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

@ -4,15 +4,14 @@ title: "Shortest Paths with Non-Negative Edge Weights"
author: Benjamin Qi
prerequisites:
- bfs
- stacks-queues
- intro-ordered
description: "Introduces Dijkstra's Algorithm for a single source shortest path as well as Floyd-Warshall for All-Pairs Shortest Path."
frequency: 3
---
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CSES", "Shortest Routes I", "1671", "Easy", false, ["SP"], "equivalent to [Kattis SSSP Non-Negative](https://open.kattis.com/problems/shortestpath1)"),
],
@ -33,12 +32,11 @@ export const metadata = {
apsp: [
new Problem("Gold", "Moortal Cowmbat", "971", "Hard", false, ["APSP", "DP"], ""),
],
}
};
## Single-Source Shortest Path
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
### Tutorial
@ -78,11 +76,11 @@ Can be done in $O(M+N\log N)$ with [Fibonacci heap](https://en.wikipedia.org/wik
### Problems
<Problems problems={metadata.problems.dijk} />
<Problems problems={problems.dijk} />
## All Pairs Shortest Path (APSP)
<Problems problems={metadata.problems.apspSam} />
<Problems problems={problems.apspSam} />
Use the *Floyd-Warshall* algorithm.
@ -112,6 +110,6 @@ just to be safe.
### Problems
<Problems problems={metadata.problems.apsp} />
<Problems problems={problems.apsp} />
(more?)

View file

@ -8,12 +8,11 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
rmqSample: [
new Problem("YS", "Static RMQ", "staticrmq", "Easy", false, [], "equivalent to [CSES Range Minimum Queries I](https://cses.fi/problemset/task/1647)"),
],
diviSample: [
diviSample: [
new Problem("ojuz", "JOI Secret", "JOI14_secret", "Easy", false, [], ""),
],
general: [
@ -21,7 +20,6 @@ export const metadata = {
new Problem("DMOJ", "Continued Fractions", "dmopc19c7p4", "Hard", false, [], ""),
new Problem("Plat", "Non-Decreasing Subsequences", "997", "Very Hard", false, [], ""),
],
}
};
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.
@ -32,7 +30,7 @@ With $O(N\log N)$ time preprocessing, we can get $O(1)$ queries.
First we'll consider the special case when $\ominus$ denotes `min`.
<Problems problems={metadata.problems.rmqSample} />
<Problems problems={problems.rmqSample} />
### Resources
@ -55,7 +53,7 @@ First we'll consider the special case when $\ominus$ denotes `min`.
## Divide & Conquer
<Problems problems={metadata.problems.diviSample} />
<Problems problems={problems.diviSample} />
**Divide & conquer** can refer to many different techniques. In this case, we use it to answer $Q$ queries offline in $O((N+Q)\log N)$ time.
@ -86,4 +84,4 @@ A data structure known as **sqrt-tree** can speed up preprocessing time to $O(N\
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -0,0 +1,61 @@
---
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, [], ""),
],
general: [
new Problem("CSES", "Playlist", "1141", "Easy", false, ["2P"], ""),
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="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.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.general} />

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("Gold", "Springboards", "995", "Hard", false, [], ""),
],
@ -20,10 +19,9 @@ export const metadata = {
new Problem("CF", "Karen & Cards", "contest/815/problem/D", "Very Hard", false, [], "For each a from p to 1, calculate the number of possible cards with that value of a."),
new Problem("CF", "GP of Korea 19 - Interesting Drug", "gym/102059/problem/K", "Very Hard", false, [], "Genfuncs not required but possibly helpful"),
]
}
};
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
<br/>
@ -78,4 +76,4 @@ ll query(int x) { auto it = m.lb(x);
<IncompleteSection />
<Problems problems={metadata.problems.problems} />
<Problems problems={problems.problems} />

123
content/4_Gold/Stacks.mdx Normal file
View file

@ -0,0 +1,123 @@
---
id: stacks
title: Stacks
author: Darren Yao
description: "Two data structures to efficently add and remove the first and last element."
prerequisites:
- intro-ds
---
import { Problem } from "../models";
export const problems = {
nearest: [
new Problem("CSES", "Nearest Smaller Values", "1645", "Easy", false, [], ""),
],
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("Gold", "Modern Art 2","743", "Hard", false, [], ""),
new Problem("Gold", "Dishwashing","922", "Hard", false, [], ""),
],
};
<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="CP1" title="2.2 - Data Structures with Built-in Libraries"> </Resource>
</Resources>
## Stacks
A stack is a **Last In First Out** (LIFO) data structure that supports three operations, all in $O(1)$ time. Think of it like a real-world stack of papers (or cards).
<LanguageSection>
<CPPSection>
### [C++](http://www.cplusplus.com/reference/stack/stack/)
- `push`: adds an element to the top of the stack
- `pop`: removes an element from the top of the stack
- `top`: retrieves the element at the top without removing it
```cpp
stack<int> s;
s.push(1); // [1]
s.push(13); // [1, 13]
s.push(7); // [1, 13, 7]
cout << s.top() << endl; // 7
s.pop(); // [1, 13]
cout << s.size() << endl; // 2
```
</CPPSection>
<JavaSection>
### Java
- `push`: adds an element to the top of the stack
- `pop`: removes an element from the top of the stack
- `peek`: retrieves the element at the top without removing it
```java
Stack<Integer> s = new Stack<Integer>();
s.push(1); // [1]
s.push(13); // [1, 13]
s.push(7); // [1, 13, 7]
System.out.println(s.peek()); // 7
s.pop(); // [1, 13]
System.out.println(s.size()); // 2
```
</JavaSection>
</LanguageSection>
## Application: Nearest Smaller Element
<Problems problems={problems.nearest} />
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$.
<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.
### Implementation
<IncompleteSection />
## Problems
<Problems problems={problems.general} />
<!--
(actually go through these and check ...)
### Stack
- UVa 00514 - Rails
- UVa 00732 - Anagram by Stack
- UVa 01062 - Containers
### Queue / Deque
- UVa 10172 - The Lonesome Cargo
- UVa 10901 - Ferry Loading III
- UVa 11034 - Ferry Loading IV
-->

View file

@ -10,8 +10,7 @@ prerequisites:
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
ex: [
new Problem("Gold", "Cownomics", "741", "Easy", false, [], ""),
],
@ -25,7 +24,6 @@ export const metadata = {
adj: [
new Problem("CF", "Berland SU Computer Network", "contest/847/problem/L", "Normal", false, [], ""),
]
}
};
## Tutorial
@ -45,7 +43,7 @@ My implementation can be found [here](https://github.com/bqi343/USACO/blob/maste
## Example: Cownomics (Gold)
<Problems problems={metadata.problems.ex} />
<Problems problems={problems.ex} />
- Use two pointers; for a fixed $l$, keep extending $r$ to the right until the positions $l\ldots r$ explain spotiness.
- Hashing gives you a way to quickly check whether two substrings of different cow types are equal. So for a single $[l,r]$ pair you can check whether it works in $O(N\log N)$ time (and you only need to check $O(M)$ of these pairs in total).
@ -55,7 +53,7 @@ My implementation can be found [here](https://github.com/bqi343/USACO/blob/maste
(elaborate)
<Problems problems={metadata.problems.adj} />
<Problems problems={problems.adj} />
-->
## Hacking
@ -66,4 +64,4 @@ My implementation can be found [here](https://github.com/bqi343/USACO/blob/maste
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -11,8 +11,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CSES", "Course Schedule", "1679", "Easy", false, []),
],
@ -26,14 +25,13 @@ export const metadata = {
new Problem("Gold", "Milking Order", "838", "Normal", false, ["TopoSort", "Binary Search"]),
new Problem("CSES", "Course Schedule II", "1681", "Hard", false, [], "equivalent to [Minimal Labels](https://codeforces.com/contest/825/problem/E)"),
],
}
};
To review, a **directed** graph consists of edges that can only be traversed in one direction. Additionally, a **acyclic** graph defines a graph which does not contain cycles, meaning you are unable to traverse across one or more edges and return to the node you started on. Putting these definitions together, a **directed acyclic** graph, sometimes abbreviated as DAG, is a graph which has edges which can only be traversed in one direction and does not contain cycles.
## Topological Sort
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
A [topological sort](https://en.wikipedia.org/wiki/Topological_sorting) of a directed acyclic graph is a linear ordering of its vertices such that for every directed edge $u\to v$ from vertex $u$ to vertex $v$, $u$ comes before $v$ in the ordering.
@ -136,7 +134,7 @@ void compute() {
One useful property of directed acyclic graphs is, as the name suggests, that no cycles exist. If we consider each node in the graph as a state, we can perform dynamic programming on the graph if we process the states in an order that guarantees for every edge $u\to v$ that $u$ is processed before $v$. Fortunately, this is the exact definition of a topological sort!
<Problems problems={metadata.problems.dp} />
<Problems problems={problems.dp} />
In this task, we must find the longest path in a DAG.
@ -459,4 +457,4 @@ public class Main {
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -12,8 +12,7 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CSES", "Subtree Queries", "1137", "Easy", false, ["Euler-Tree"], "equivalent to https://judge.yosupo.jp/problem/vertex_add_subtree_sum"),
new Problem("CSES", "Path Queries", "1138", "Easy", false, ["Euler-Tree","PURS"], "equivalent to https://judge.yosupo.jp/problem/vertex_add_path_sum"),
@ -29,12 +28,11 @@ export const metadata = {
new Problem("ojuz", "IOI - Regions", "IOI09_regions", "Hard", false, ["Euler-Tree", "Binary Search"], ""),
new Problem("Plat", "Snow-Cow", "973", "Hard", false, ["Euler-Tree","PURS"], ""),
]
}
};
## Introduction
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
If we can preprocess a rooted tree such that every subtree corresponds to a contiguous range on an array, we can do updates and range queries on it!
@ -50,7 +48,7 @@ If we can preprocess a rooted tree such that every subtree corresponds to a cont
## LCA
<Problems problems={metadata.problems.lca} />
<Problems problems={problems.lca} />
### Tutorial
@ -65,4 +63,4 @@ If we can preprocess a rooted tree such that every subtree corresponds to a cont
## Problems
<Problems problems={metadata.problems.problems} />
<Problems problems={problems.problems} />

View file

@ -8,8 +8,7 @@ description: "Extending Range Queries to 2D (and beyond)."
frequency: 1
---
export const metadata = {
problems: {
export const problems = {
bitSam: [
new Problem("CSES", "Forest Queries II", "1739", "Easy", false, ["2D BIT"], "[thecodingwizard's implementation](https://github.com/thecodingwizard/competitive-programming/blob/master/cses/Forest%20Queries%20II.cpp)"),
],
@ -29,7 +28,6 @@ export const metadata = {
new Problem("ojuz", "IOI 2013 - Game", "IOI13_game", "Very Hard", false, ["2D Seg"], "Alternatively, use BBST in place of sparse segment tree (see Advanced - Treaps)"),
new Problem("ojuz", "JOI - Golf", "JOI17_golf", "Very Hard", false, ["Seg"], ""),
],
}
};
See [my implementations](https://github.com/bqi343/USACO/tree/master/Implementations/content/data-structures/2D%20Range%20Queries%20(15.2)).
@ -44,7 +42,7 @@ See [my implementations](https://github.com/bqi343/USACO/tree/master/Implementat
## 2D BIT
<Problems problems={metadata.problems.bitSam} />
<Problems problems={problems.bitSam} />
### Tutorial
@ -55,7 +53,7 @@ See [my implementations](https://github.com/bqi343/USACO/tree/master/Implementat
### Problems
<Problems problems={metadata.problems.bit} />
<Problems problems={problems.bit} />
<Optional title="Range Update and Range Query in Higher Dimensions">
@ -67,7 +65,7 @@ Lazy propagation on segment trees does not extend to higher dimensions. However,
## 2D Offline Sum Queries
<Problems problems={metadata.problems.offSam} />
<Problems problems={problems.offSam} />
The intended complexity is $O(N\log^2 N)$ with a good constant factor. This requires updating points and querying rectangle sums $N$ times for points with coordinates in the range $[1,N]$. However The 2D BITs mentioned above use $O(N^2)$ memory, which is too much. Since we know all of the updates and queries beforehand, we can reduce the memory usage while maintaining a decent constant factor.
@ -93,7 +91,7 @@ It's a bit difficult to pass the above problem within the time limit. Make sure
### Problems
<Problems problems={metadata.problems.off} />
<Problems problems={problems.off} />
## 2D Segment Tree
@ -124,4 +122,4 @@ To resolve this, reduce the memory usage of sparse segment tree while maintaing
Can also try the USACO problems from above.
<Problems problems={metadata.problems.seg} />
<Problems problems={problems.seg} />

View file

@ -10,8 +10,7 @@ frequency: 1
---
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sam2: [
new Problem("YS", "Two-Edge-Connected Components", "two_edge_connected_components", "Easy", false, [], ""),
],
@ -31,7 +30,6 @@ export const metadata = {
new Problem("DMOJ", "Investment", "tle17c1p6", "Hard", false, [], ""),
new Problem("ojuz", "CEOI - Pipes", "CEOI15_pipes", "Hard", false, [], ""),
],
}
};
<Resources>
@ -40,13 +38,13 @@ export const metadata = {
## 2-Edge-Connected Components
<Problems problems={metadata.problems.sam2} />
<Problems problems={problems.sam2} />
(implementation)
### With DSU
<Problems problems={metadata.problems.disrupt} />
<Problems problems={problems.disrupt} />
The analysis for the above problem mentions an $O(m\alpha(n))$ solution. Although this is not a two-connected component problem, we can in fact use DSU to generate two-connected components.
@ -91,7 +89,6 @@ struct TwoEdgeCC {
void gen() {
F0R(i,N) if (par[i] == -1) dfs(i); // independently for each connected component
DSU.init(N); trav(t,extra) ad(t.f,t.s); // add non-spanning edges
}
};
```
@ -99,13 +96,13 @@ struct TwoEdgeCC {
### Problems
<Problems problems={metadata.problems.probs2} />
<Problems problems={problems.probs2} />
- SRM 787 1000
## [Biconnected Components](https://en.wikipedia.org/wiki/Biconnected_component)
<Problems problems={metadata.problems.bccSam} />
<Problems problems={problems.bccSam} />
note that BCCs contain EDGES not VERTICES
@ -125,4 +122,4 @@ Related topics include
### Problems
<Problems problems={metadata.problems.gen} />
<Problems problems={problems.gen} />

View file

@ -8,8 +8,7 @@ frequency: 3
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CSES", "Company Queries I", "1687", "Easy", false, ["Binary Jumping"], ""),
],
@ -31,16 +30,15 @@ export const metadata = {
new Problem("Plat", "Gathering", "866", "Hard", false, ["LCA"], "interactive!!"),
new Problem("Plat", "Exercise", "901", "Very Hard", false, ["LCA"], ""),
]
}
};
## Binary Jumping
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
## Lowest Common Ancestor
<Problems problems={metadata.problems.lca} />
<Problems problems={problems.lca} />
### Tutorial
@ -59,4 +57,4 @@ export const metadata = {
### Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -10,8 +10,7 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
school: [
new Problem("CSES", "School Excursion", "1706", "Easy", false, ["Knapsack", "Bitset"], ""),
],
@ -29,7 +28,6 @@ export const metadata = {
new Problem("CSES", "BOI - Nautilus", "https://cses.fi/247/submit/B", "Normal", false, ["Bitset"], ""),
new Problem("ojuz", "IZhO - Bootfall", "IZhO17_bootfall", "Hard", false, ["Knapsack", "Bitset"], ""),
],
}
};
## Tutorial
@ -42,7 +40,7 @@ tl;dr some operations are 32x-64x faster compared to a boolean array. See the [C
## Knapsack
<Problems problems={metadata.problems.school} />
<Problems problems={problems.school} />
Of course, the first step is to generate the sizes of each connected component.
@ -103,7 +101,7 @@ int main() {
## Cowpatibility (Gold)
<Problems problems={metadata.problems.cow} />
<Problems problems={problems.cow} />
Label the cows from $0\ldots N-1$. For two cows $x$ and $y$ set `adj[x][y]=1` if they share a common flavor. Then the number of pairs of cows that are compatible (counting each pair where $x$ and $y$ are distinct twice) is equal to the sum of `adj[x].count()` over all $x$. It remains to compute `adj[x]` for all $x$.
@ -189,7 +187,7 @@ Apparently no test case contains more than $25000$ distinct colors, so we don't
## Lots of Triangles
<Problems problems={metadata.problems.lots} />
<Problems problems={problems.lots} />
First, we read in the input data. `cross(a,b,c)` is positive iff `c` lies to the left of the line from `a` to `b`.
@ -350,10 +348,10 @@ Operations such as `_Find_first()` and `_Find_next()` mentioned in Errichto's bl
Regarding the last application:
<Problems problems={metadata.problems.bfs} />
<Problems problems={problems.bfs} />
In USACO Camp, this problem appeared with $N\le 10^5$ and a large time limit ...
## Additional Problems
<Problems problems={metadata.problems.ad} />
<Problems problems={problems.ad} />

View file

@ -18,8 +18,7 @@ TODO:
import { Problem } from "../models";
export const metadata = {
problems: {
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"], ""),
@ -34,7 +33,6 @@ export const metadata = {
new Problem("ojuz", "JOI - Synchronization", "JOI13_synchronization", "Hard", false, ["Centroid", "Small to Large"], "Looks like $O(N \log^3 N)$ is very fast!"),
new Problem("Plat", "At Large", "793", "Very Hard", false, ["Centroid"], "tight time limit"),
]
}
};
## Centroid Decomposition
@ -134,6 +132,6 @@ public void centroid(int n)
### Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
*Note:* Unfortunately, it seems like constant factor is especially important for DMOJ. :|

View file

@ -10,8 +10,7 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("Kattis", "Convex Hull", "convexhull", "Easy", false, ["convex"], ""),
],
@ -32,12 +31,11 @@ export const metadata = {
new Problem("Plat", "Circular Barn", "626", "Hard", false, ["DP", "convex"], ""),
new Problem("Plat", "Falling Portals", "998", "Very Hard", false, ["convex"], ""),
],
}
};
## [Convex Hull](https://en.wikipedia.org/wiki/Convex_hull_algorithms)
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
### Tutorial
@ -49,17 +47,17 @@ export const metadata = {
- [Wikipedia](https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain)
- [My Implementation](https://github.com/bqi343/USACO/blob/master/Implementations/content/geometry%20(13)/Polygons/ConvexHull%20(13.2).h)
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
## Rotating Caliphers
<Problems problems={metadata.problems.sample2} />
<Problems problems={problems.sample2} />
<Resources>
<Resource source="CF" title="Rotating calipers technique and applications" url="blog/entry/46162"> </Resource>
</Resources>
<Problems problems={metadata.problems.rotating} />
<Problems problems={problems.rotating} />
## Convex Hull Trick
@ -68,6 +66,6 @@ export const metadata = {
<Resource source="CF" title="Convex Hull Trick - Geo Being Useful" url="blog/entry/63823" starred> </Resource>
</Resources>
<Problems problems={metadata.problems.cht} />
<Problems problems={problems.cht} />
https://codeforces.com/contest/1083/problem/E

View file

@ -11,8 +11,7 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
general: [
new Problem("AC", "Matching", "https://atcoder.jp/contests/dp/tasks/dp_o?lang=en", "Easy", false, ["Bitmasks"], ""),
new Problem("CSES", "Hamiltonian Flights", "1690", "Easy", false, ["Bitmasks"], ""),
@ -29,7 +28,6 @@ export const metadata = {
new Problem("CF", "Guards in the Storehouse", "problemset/problem/845/F", "Normal", false, [], ""),
new Problem("Plat", "Compound Escape", "949", "Very Hard", false, [], ""),
],
}
};
<Info title="Pro Tip">
@ -50,7 +48,7 @@ You can often use this to solve subtasks.
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
## DP on Broken Profile
@ -60,4 +58,4 @@ You can often use this to solve subtasks.
(fill in? more probs?)
<Problems problems={metadata.problems.broken} />
<Problems problems={problems.broken} />

View file

@ -10,8 +10,7 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
general: [
new Problem("Gold", "248", "647", "Easy", false, ["Range DP"]),
new Problem("CSES", "Empty String", "1080", "Normal", false, ["Range DP"]),
@ -19,7 +18,6 @@ export const metadata = {
new Problem("Plat", "Greedy Pie Eaters", "972", "Hard", false, ["Range DP"]),
new Problem("Plat", "Subsequence Reversal", "698", "Hard", false, ["Range DP"]),
]
}
};
## Tutorial
@ -28,6 +26,6 @@ export const metadata = {
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
* TC SRM 787 500

View file

@ -12,8 +12,7 @@ Has not appeared on a recent USACO contest.
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sam: [
new Problem("CSES", "Mail Delivery (Undirected)", "1691", "Easy", false, ["Euler Tour"], ""),
new Problem("CSES", "Teleporters (Directed)", "1693", "Easy", false, ["Euler Tour"], ""),
@ -23,12 +22,11 @@ export const metadata = {
new Problem("CF", "Johnny and Megan's Necklace", "contest/1361/problem/C", "Normal", false, ["Euler Tour"], ""),
new Problem("CF", "Data Center Drama", "contest/528/problem/C", "Normal", false, ["Euler Tour"], ""),
]
}
};
### Standard
<Problems problems={metadata.problems.sam} />
<Problems problems={problems.sam} />
### Tutorial
@ -36,4 +34,4 @@ export const metadata = {
### Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
e1: [
new Problem("DMOJ", "Land of the Rainbow Gold", "apio17p1", "Hard", false, [],""),
],
@ -21,17 +20,16 @@ export const metadata = {
other: [
new Problem("Kattis", "Island Archipelago", "https://utipc20s.kattis.com/problems/utipc20s.islandarchipelago", "Very Hard", false, [],""),
],
}
};
## Example 1
<Problems problems={metadata.problems.e1} />
<Problems problems={problems.e1} />
## Example 2
<Problems problems={metadata.problems.e2} />
<Problems problems={problems.e2} />
Extension:
<Problems problems={metadata.problems.other} />
<Problems problems={problems.other} />

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
maxSam: [
new Problem("CSES", "Download Speed", "1694", "Easy", false, ["Max Flow"], ""),
],
@ -35,12 +34,11 @@ export const metadata = {
new Problem("CF", "Goods Transportation", "problemset/problem/724/E", "Hard", false, [], ""),
new Problem("AC", "ARC E - MUL", "http://arc085.contest.atcoder.jp/tasks/arc085_c", "Hard", false, [], ""),
]
}
};
## Maximum Flow
<Problems problems={metadata.problems.maxSam} />
<Problems problems={problems.maxSam} />
### Tutorial
@ -51,15 +49,15 @@ export const metadata = {
### Problems
<Problems problems={metadata.problems.flow} />
<Problems problems={problems.flow} />
## Bipartite Matching
<Problems problems={metadata.problems.match} />
<Problems problems={problems.match} />
## Dinic's Algorithm
<Problems problems={metadata.problems.dinic} />
<Problems problems={problems.dinic} />
Hopcroft-Karp Bipartite Matching?
@ -75,7 +73,7 @@ However, the standard implementation of Dinic's is (almost) always fast enough.
## Min-Cut Max Flow
<Problems problems={metadata.problems.minEx} />
<Problems problems={problems.minEx} />
(show equivalence)
@ -89,4 +87,4 @@ https://maps20.kattis.com/problems/thewrathofkahn
## Problems
<Problems problems={metadata.problems.cut} />
<Problems problems={problems.cut} />

View file

@ -11,8 +11,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("Plat", "Robotic Cow Herd", "674", "Normal", false, [], ""),
],
@ -21,7 +20,6 @@ export const metadata = {
new Problem("DMOJ", "CCO - Shopping Plans", "cco20p6", "Very Hard", false, [], "Generalization of RoboHerd."),
new Problem("YS", "K-th Shortest Walk", "k_shortest_walk", "Very Hard", false, [], "(english description?), [Relevant Paper](https://www.ics.uci.edu/~eppstein/pubs/Epp-SJC-98.pdf), Can use to solve RoboHerd!"),
],
}
};
@ -147,7 +145,7 @@ int main() {
## Robotic Cow Herd
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
As with the analysis, for each location you should
@ -308,4 +306,4 @@ int main() {
## Other Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -7,8 +7,7 @@ description: Basic setup for geometry problems.
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
standard: [
new Problem("YS", "Sort Points by Argument", "sort_points_by_argument", "Intro", false, [], ""),
new Problem("Kattis", "Segment Intersection", "segmentintersection", "Intro", false, [], ""),
@ -23,7 +22,6 @@ export const metadata = {
new Problem("Kattis", "Max Collinear", "maxcolinear", "Easy", false, [], ""),
new Problem("Kattis", "Birthday Cake", "birthdaycake", "Easy", false, [], ""),
]
}
};
## Primitives
@ -50,11 +48,11 @@ You should know basic operations like cross product and dot product.
<Resource source="IUSACO" title="14.2 - Segment Intersection"></Resource>
</Resources>
<Problems problems={metadata.problems.standard} />
<Problems problems={problems.standard} />
### Misc Problems
<Problems problems={metadata.problems.other} />
<Problems problems={problems.other} />
- [Racing Off Track](https://open.kattis.com/contests/acpc17open/problems/racingofftrack) (link doesn't work ...)
- [TopCoder Watchtower](https://community.topcoder.com/stat?c=problem_statement&pm=2014&rd=4685)

View file

@ -11,8 +11,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("CSES", "Company Queries II", "1688", "Intro|Easy", false, ["LCA"], "Pure implementation; see Benq's library code, it has a function for LCA. Though this problem can be solved with binary lifting as well, you should do it with HLD to get practice."),
],
@ -28,10 +27,9 @@ export const metadata = {
new Problem("ojuz", "JOI - Synchronization", "JOI13_synchronization", "Hard", false, ["HLD"], "$O(N\\log N)$ :D"),
new Problem("ojuz", "JOI - Cats or Dogs", "JOI18_catdog", "Very Hard", false, ["HLD"], ""),
],
}
};
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
## Tutorial
@ -50,4 +48,4 @@ export const metadata = {
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("YS", "Line Add Get Min", "line_add_get_min", "Normal", false, [], ""),
],
@ -24,7 +23,6 @@ export const metadata = {
new Problem("TOKI", "Mall & Transportation", "https://tlx.toki.id/contests/troc-13-div-1/problems/D", "Very Hard", false, [], ""),
new Problem("Old Gold", "Fencing the Herd", "534", "Very Hard", false, [], ""),
]
}
};
## Half-Plane Intersection
@ -34,11 +32,11 @@ export const metadata = {
<Resource source="Petr" title="Linear Half-Plane Intersection" url="https://petr-mitrichev.blogspot.com/2016/07/a-half-plane-week.html" starred>expected linear!</Resource>
</Resources>
<Problems problems={metadata.problems.half} />
<Problems problems={problems.half} />
## LineContainer
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
<Resources>
<Resource source="KACTL" title="LineContainer" url="https://github.com/kth-competitive-programming/kactl/blob/master/content/data-structures/LineContainer.h" starred>code</Resource>
@ -48,6 +46,6 @@ export const metadata = {
## Problems
<Problems problems={metadata.problems.probs} />
<Problems problems={problems.probs} />
https://atcoder.jp/contests/arc066/tasks/arc066_d

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("Plat", "Tall Barn", "697", "Easy", false, [], ""),
],
@ -20,12 +19,11 @@ export const metadata = {
new Problem("Kattis", "Blazing New Trails", "blazingnewtrails", "Normal", false, [], ""),
new Problem("ojuz", "Aliens", "IOI16_aliens", "Hard", false, [], ""),
]
}
};
adding lambda\*smth
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
## Tutorial
@ -35,4 +33,4 @@ adding lambda\*smth
## Problems
<Problems problems={metadata.problems.probs} />
<Problems problems={problems.probs} />

View file

@ -11,8 +11,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sam: [
new Problem("CSES", "Distinct Colors", "1139", "Intro", false, ["Merging"]),
],
@ -23,7 +22,6 @@ export const metadata = {
new Problem("Plat", "Disruption", "842", "Normal", false, ["Merging"]),
new Problem("POI", "Tree Rotations", "https://szkopul.edu.pl/problemset/problem/sUe3qzxBtasek-RAWmZaxY_p/site/?key=statement", "Normal", false, ["Merging", "Indexed Set"], ""),
],
}
};
## Additional Reading
@ -38,7 +36,7 @@ export const metadata = {
Obviously [linked lists](http://www.cplusplus.com/reference/list/list/splice/) can be merged in $O(1)$ time. But what about sets or vectors?
<Problems problems={metadata.problems.sam} />
<Problems problems={problems.sam} />
Let's consider a tree rooted at node $1$, where each node has a color.
@ -122,7 +120,7 @@ A set doesn't have to be an `std::set`. Many data structures can be merged, such
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
<Spoiler title="Solution to Promotion Counting">

View file

@ -10,8 +10,7 @@ frequency: 0
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
rollback: [
new Problem("YS", "Persistent Union Find", "persistent_unionfind", "Normal", false, [], ""),
new Problem("YS", "Vertex Add Component Sum", "dynamic_graph_vertex_add_component_sum", "Hard", false, [], ""),
@ -20,7 +19,6 @@ export const metadata = {
ins: [
new Problem("Old Gold", "Fencing the Herd", "534", "Hard", false, [], ""),
],
}
};
### DSU With Rollback
@ -29,7 +27,7 @@ no path compression
(tutorial?)
<Problems problems={metadata.problems.rollback} />
<Problems problems={problems.rollback} />
<!-- ## Dynamic Insertion
@ -37,4 +35,4 @@ mention sqrt
(online Aho-Corasick)
<Problems problems={metadata.problems.ins} /> -->
<Problems problems={problems.ins} /> -->

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
bitSample: [
new Problem("SPOJ", "Horrible Queries", "HORRIBLE", "Easy", false, ["BIT-Range"], ""),
],
@ -34,12 +33,11 @@ export const metadata = {
segTreeBeats: [
new Problem("YS", "Range Chmin Chmax Add Range Sum", "range_chmin_chmax_add_range_sum", "Very Hard", false, ["SegTreeBeats"], ""),
],
}
};
## BIT Revisited
<Problems problems={metadata.problems.bitSample} />
<Problems problems={problems.bitSample} />
Binary Indexed Trees can support range increments in addition to range sum queries.
@ -54,11 +52,11 @@ Binary Indexed Trees can support range increments in addition to range sum queri
### Problems
<Problems problems={metadata.problems.bitProb} />
<Problems problems={problems.bitProb} />
## Lazy Segment Tree
<Problems problems={metadata.problems.lazySample} />
<Problems problems={problems.lazySample} />
### Tutorial
@ -71,7 +69,7 @@ Binary Indexed Trees can support range increments in addition to range sum queri
### Problems
<Problems problems={metadata.problems.lazySegTree} />
<Problems problems={problems.lazySegTree} />
## Lazy Segment Tree - Counting Minimums
@ -79,4 +77,4 @@ use segment tree that keeps track of minimum and # of minimums
(describe)
<Problems problems={metadata.problems.lazySegCnt} />
<Problems problems={problems.lazySegCnt} />

View file

@ -11,8 +11,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
ex: [
new Problem("CSES", "Planets & Kingdoms", "1683", "Easy", false, [], ""),
],
@ -27,12 +26,11 @@ export const metadata = {
satEx: [
new Problem("CSES", "Giant Pizza", "1684", "Normal", false, [], "")
],
}
};
## SCCs
<Problems problems={metadata.problems.ex} />
<Problems problems={problems.ex} />
### Tutorial
@ -49,11 +47,11 @@ export const metadata = {
### Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
## 2-SAT
<Problems problems={metadata.problems.satEx} />
<Problems problems={problems.satEx} />
(impl)

View file

@ -10,8 +10,7 @@ frequency: 0
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sam: [
new Problem("Kattis", "SSSP Negative", "shortestpath3", "Easy", false, [], ""),
new Problem("Kattis", "APSP (with negative weights)", "allpairspath", "Easy", false, [], ""),
@ -24,10 +23,9 @@ export const metadata = {
linear: [
new Problem("ojuz", "Restore Array", "RMI19_restore", "Normal", false, [], "similar to [Art](https://codeforces.com/gym/102394/problem/A)"),
],
}
};
<Problems problems={metadata.problems.sam} />
<Problems problems={problems.sam} />
<br/>
@ -46,7 +44,7 @@ Can also use [Shortest Path Faster Algorithm](https://en.wikipedia.org/wiki/Shor
### Problems
<Problems problems={metadata.problems.probs} />
<Problems problems={problems.probs} />
## Simple Linear Programming
@ -64,4 +62,4 @@ You can also use shortest path algorithms to solve the following problem (a very
### Problems
<Problems problems={metadata.problems.linear} />
<Problems problems={problems.linear} />

View file

@ -10,8 +10,7 @@ frequency: 3
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
walkSam: [
new Problem("CSES", "Hotel Queries", "1143", "Easy", false, ["PURQ"], "walk"),
],
@ -35,12 +34,11 @@ export const metadata = {
new Problem("Kattis", "Easy Query", "easyquery", "Hard", false, ["Wavelet"], ""),
new Problem("DMOJ", "Ninjaclasher's Wrath 2", "globexcup19s4", "Hard", false, ["Wavelet"], ""),
],
}
};
## Walking on a Segment Tree
<Problems problems={metadata.problems.walkSam} />
<Problems problems={problems.walkSam} />
You want to support queries of the following form on an array $a_1,\ldots,a_N$ (along with point updates).
@ -48,19 +46,19 @@ You want to support queries of the following form on an array $a_1,\ldots,a_N$ (
Of course, you can do this in $O(\log^2N)$ time with a max segment tree and binary searching on the first $i$ such that $\max(a_1,\ldots,a_i)\ge x$. But try to do this in $O(\log N)$ time.
<Problems problems={metadata.problems.walk} />
<Problems problems={problems.walk} />
## Combining
<Problems problems={metadata.problems.combSam} />
<Problems problems={problems.combSam} />
(solution to above problem)
<Problems problems={metadata.problems.comb} />
<Problems problems={problems.comb} />
## Wavelet Tree
<Problems problems={metadata.problems.waveletSam} />
<Problems problems={problems.waveletSam} />
### Tutorial
@ -70,4 +68,4 @@ Of course, you can do this in $O(\log^2N)$ time with a max segment tree and bina
### Problems
<Problems problems={metadata.problems.wavelet} />
<Problems problems={problems.wavelet} />

View file

@ -11,8 +11,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
ex: [
new Problem("CF", "Problem Without a Legend", "contest/713/problem/C", "Easy", false, ["Slope Trick"], ""),
],
@ -34,7 +33,6 @@ export const metadata = {
new Problem("CF", "April Fools' Problem", "contest/802/problem/O", "Very Hard", false, ["Slope Trick"], "binary search on top of slope trick"),
new Problem("ICPC World Finals", "Conquer the World", "https://icpc.kattis.com/problems/conquertheworld", "Very Hard", false, ["Slope Trick", "Small to Large"], "ICPC world finals, 0 solves in contest - \"Potatoes\" on tree!!"),
],
}
};
## Tutorials
@ -61,13 +59,13 @@ Usually you can come up with a slower (usually $O(N^2)$) DP first and then optim
The rest of this module assumes that you know the basic idea of this trick. In particular, you should be at least somewhat familiar with the $O(N\log N)$ time solution to the first problem in zscoder's tutorial:
<Problems problems={metadata.problems.ex} />
<Problems problems={problems.ex} />
It's ok if you found the explanations confusing; the example below should help clarify.
## Buy Low Sell High
<Problems problems={metadata.problems.buy} />
<Problems problems={problems.buy} />
### Slow Solution
@ -212,7 +210,7 @@ int main() {
## Potatoes & Fertilizers
<Problems problems={metadata.problems.potatoes} />
<Problems problems={problems.potatoes} />
### Simplifying the Problem
@ -290,7 +288,7 @@ int main() {
## USACO Landscaping
<Problems problems={metadata.problems.landscaping} />
<Problems problems={problems.landscaping} />
This looks similar to the previous task (we're moving dirt instead of fertilizer), so it's not too hard to guess that slope trick is applicable.
@ -367,4 +365,4 @@ We can solve this problem when $\sum A_i+\sum B_i$ is not so small with lazy bal
## Problems
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />

View file

@ -7,8 +7,7 @@ frequency: 1
---
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
fst: [
new Problem("CF", "Tree Queries", "contest/1254/problem/D", "Hard", false, [], ""),
new Problem("wcipeg", "COI 08-Otoci", "https://wcipeg.com/problem/coi08p2", "Hard", false, ["HLD"], "Editorial rebuilds HLD after certain # of updates ..."),
@ -22,7 +21,6 @@ export const metadata = {
other: [
new Problem("Plat", "Train Tracking", "841", "Insane", false, [], ""),
]
}
};
<IncompleteSection />
@ -35,7 +33,7 @@ partitioning into sqrt blocks (each block can have some sort of data structure .
optimization tips? (ez to get TLE with bad constant ..., can get AC with suboptimal complexity ...)
<Problems problems={metadata.problems.fst} />
<Problems problems={problems.fst} />
## Mo's
@ -50,7 +48,7 @@ optimization tips? (ez to get TLE with bad constant ..., can get AC with subopti
### Block Tree
<Problems problems={metadata.problems.block} />
<Problems problems={problems.block} />
<Resources>
<Resource source="CF" title="Block Tree" url="blog/entry/46843"></Resource>
@ -58,4 +56,4 @@ optimization tips? (ez to get TLE with bad constant ..., can get AC with subopti
### Train Tracking
<Problems problems={metadata.problems.other} />
<Problems problems={problems.other} />

View file

@ -8,8 +8,7 @@ description: Knuth-Morris-Pratt and Z Algorithms (and a few more related topics)
frequency: 1
---
export const metadata = {
problems: {
export const problems = {
KMP: [
new Problem("Kattis", "String Matching", "problems/stringmatching", "Easy", false, ["Strings"], "Naive KMP works. Just be careful about I/O"),
new Problem("POJ", "(USACO Gold 05) Cow Patterns", "http://poj.org/problem?id=3167", "Hard", false, ["Strings"], "Run KMP, except each state needs to be considered as not only a length, but also mapping of pattern to # of spots"),
@ -36,7 +35,6 @@ export const metadata = {
pal: [
new Problem("ojuz", "Palindrome", "APIO14_palindrome", "Easy", false, [], ""),
]
}
};
## General
@ -59,7 +57,7 @@ Specifically, it computes the longest substring that is both a prefix and suffix
<Resource source="TC" title="String Searching" url="introduction-to-string-searching-algorithms"></Resource>
</Resources>
<Problems problems={metadata.problems.KMP} />
<Problems problems={problems.KMP} />
## Z Algorithm
@ -71,7 +69,7 @@ The **Z-Algorithm** is another linear time string comparison algorithm like KMP,
<Resource source="CF" title="Z Algorithm" url="blog/entry/3107"></Resource>
</Resources>
<Problems problems={metadata.problems.Z} />
<Problems problems={problems.Z} />
## Manacher
@ -88,7 +86,7 @@ It can determine the longest palindrome centered at each character.
If s[l, r] is a palindrome, then s[l+1, r-1] is as well.
</Info>
<Problems problems={metadata.problems.mana} />
<Problems problems={problems.mana} />
# Multiple Strings
@ -104,7 +102,7 @@ This means that every prefix of a string is an ancestor of that string's node.
<Resource source="PAPS" title="14.1 - Tries"></Resource>
</Resources>
<Problems problems={metadata.problems.trie} />
<Problems problems={problems.trie} />
## Aho-Corasick
@ -122,7 +120,7 @@ Build the entire trie first, and then run a *BFS* to construct the fail array.
<Resource source="GFG" title="Aho-Corasick for Pattern Searching" url="aho-corasick-algorithm-pattern-searching"></Resource>
</Resources>
<Problems problems={metadata.problems.aho} />
<Problems problems={problems.aho} />
## Palindromic Tree
@ -132,6 +130,6 @@ Build the entire trie first, and then run a *BFS* to construct the fail array.
<Resource source="CF" title="adamant - Palindromic Tree" url="blog/entry/13959"></Resource>
</Resources>
<Problems problems={metadata.problems.pal} />
<Problems problems={problems.pal} />
DMOJ thing

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
sample: [
new Problem("YS", "Suffix Array", "suffixarray", "Easy", false, [], ""),
],
@ -28,7 +27,6 @@ export const metadata = {
runSam: [
new Problem("YS", "Run Enumerate", "runenumerate", "Hard", false, [], ""),
]
}
};
## Resources
@ -41,7 +39,7 @@ export const metadata = {
## Suffix Array
<Problems problems={metadata.problems.sample} />
<Problems problems={problems.sample} />
### Implementations
@ -53,11 +51,11 @@ export const metadata = {
## LCP Array
<Problems problems={metadata.problems.lcpSam} />
<Problems problems={problems.lcpSam} />
Quickly compute longest common prefix of two suffixes.
<Problems problems={metadata.problems.lcp} />
<Problems problems={problems.lcp} />
## Inverse Burrows-Wheeler
@ -67,7 +65,7 @@ Quickly compute longest common prefix of two suffixes.
CSES Guide?
<Problems problems={metadata.problems.burSam} />
<Problems problems={problems.burSam} />
## Run Enumerate
@ -77,5 +75,5 @@ CSES Guide?
(describe how to do easily w/ suffix array)
<Problems problems={metadata.problems.runSam} />
<Problems problems={problems.runSam} />

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
closest: [
new Problem("Kattis", "Closest Pair", "closestpair2", "Normal", false, [], ""),
],
@ -24,7 +23,6 @@ export const metadata = {
man: [
new Problem("CSA", "The Sprawl", "the-sprawl", "Hard", false, [], ""),
]
}
};
(what's line sweep?)
@ -36,7 +34,7 @@ export const metadata = {
## Closest Pair
<Problems problems={metadata.problems.closest} />
<Problems problems={problems.closest} />
(explanation? KACTL?)
@ -44,18 +42,18 @@ export const metadata = {
(refer to previous module)
<Problems problems={metadata.problems.seg} />
<Problems problems={problems.seg} />
(filling in the details?)
## Manhattan MST
<Problems problems={metadata.problems.manSam} />
<Problems problems={problems.manSam} />
(KACTL code)
explanation? topcoder prob has
<Problems problems={metadata.problems.man} />
<Problems problems={problems.man} />
TC 760 ComponentsForever

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
kat: [
new Problem("Kattis","Modular Arithmetic", "modulararithmetic"),
],
@ -19,7 +18,6 @@ export const metadata = {
new Problem("Kattis","Chinese Remainder", "chineseremainder"),
new Problem("Kattis","Chinese Remainder (non-relatively prime moduli)", "generalchineseremainder"),
],
}
};
## Euclidean Algorithm
@ -140,7 +138,7 @@ Note that this works when $a,b$ are quite large (say, $\approx 2^{60}$) and we w
<Resource source="cp-algo" url="algebra/module-inverse.html" title="Modular Inverse"> </Resource>
</Resources>
<Problems problems={metadata.problems.kat} />
<Problems problems={problems.kat} />
It seems that when multiplication / division is involved in this problem, $n^2 < \texttt{LLONG\_MAX}$.
@ -176,4 +174,4 @@ int main() {
<Resource source="cp-algo" url="algebra/chinese-remainder-theorem.html" title="Chinese Remainder Theorem"></Resource>
</Resources>
<Problems problems={metadata.problems.crt} />
<Problems problems={problems.crt} />

View file

@ -9,8 +9,7 @@ frequency: 0
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
ys: [
new Problem("YS", "Partition Function", "partition_function", "?", false, [], ""),
new Problem("YS", "Bernoulli Number", "bernoulli_number", "?", false, [], ""),
@ -19,7 +18,6 @@ export const metadata = {
new Problem("Plat", "Tree Depth", "974", "Hard", false, ["genfunc"], ""),
new Problem("Plat", "Exercise", "1045", "Hard", false, ["permutation"], "genfuncs not required but possibly helpful"),
],
}
};
## More Complex Operations
@ -36,13 +34,13 @@ export const metadata = {
### Problems
<Problems problems={metadata.problems.ys} />
<Problems problems={problems.ys} />
## Counting
No advanced knowledge about generating functions is required for either of these problems.
<Problems problems={metadata.problems.general} />
<Problems problems={problems.general} />
However, these do:

View file

@ -10,8 +10,7 @@ frequency: 0
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
hungry: [
new Problem("DMOJ", "Hungry Squirrels", "wac4p6", "Normal", false, [], ""),
],
@ -21,10 +20,9 @@ export const metadata = {
new Problem("CF", "Incorrect Flow", "contest/708/problem/D", "Normal", false, [], ""),
new Problem("AC", "Multi-Path Story", "https://atcoder.jp/contests/jag2013summer-day4/tasks/icpc2013summer_day4_i", "Normal", false, [], ""),
],
}
};
<Problems problems={metadata.problems.hungry} />
<Problems problems={problems.hungry} />
### Tutorial
@ -34,4 +32,4 @@ export const metadata = {
### Problems
<Problems problems={metadata.problems.lower} />
<Problems problems={problems.lower} />

View file

@ -10,8 +10,7 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
lctSam: [
new Problem("YS", "Vertex Add Path Sum", "dynamic_tree_vertex_add_path_sum", "Normal", false, ["LCT"], ""),
],
@ -38,7 +37,6 @@ export const metadata = {
new Problem("CF", "Old Driver Tree", "contest/1172/problem/E", "Hard", false, ["LCT"], ""),
new Problem("DMOJ", "Dynamic Tree Test", "ds5", "Very Hard", false, ["LCT"], ""),
]
}
};
## Splay Tree
@ -54,7 +52,7 @@ export const metadata = {
## Link Cut Tree - Paths
<Problems problems={metadata.problems.lctSam} />
<Problems problems={problems.lctSam} />
### Tutorial
@ -65,7 +63,7 @@ export const metadata = {
### Problems
<Problems problems={metadata.problems.lct} />
<Problems problems={problems.lct} />
<!--
@ -84,7 +82,7 @@ export const metadata = {
## Link Cut Tree - Subtrees
<Problems problems={metadata.problems.subSam} />
<Problems problems={problems.subSam} />
### Tutorial
@ -92,4 +90,4 @@ export const metadata = {
### Problems
<Problems problems={metadata.problems.sub} />
<Problems problems={problems.sub} />

View file

@ -10,12 +10,10 @@ frequency: 1
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
segTreeBeats: [
new Problem("YS", "Range Chmin Chmax Add Range Sum", "range_chmin_chmax_add_range_sum", "Hard", false, ["SegTreeBeats"], ""),
],
}
};
### Tutorial
@ -26,6 +24,6 @@ export const metadata = {
### Problems
<Problems problems={metadata.problems.segTreeBeats} />
<Problems problems={problems.segTreeBeats} />
(300iq insane problem??)

View file

@ -8,15 +8,13 @@ prerequisites:
frequency: 0
---
export const metadata = {
problems: {
export const problems = {
auto: [
new Problem("Plat", "Standing Out from the Herd", "768", "Hard", false, [], ""),
],
tree: [
new Problem("CF", "Security", "contest/1037/problem/H", "Hard", false, ["Suffix Tree"], ""),
]
}
};
## Suffix Automaton
@ -38,7 +36,7 @@ Most problems can be solved with Suffix Arrays, Suffix Automata, or Suffix Trees
### Problems
<Problems problems={metadata.problems.auto} />
<Problems problems={problems.auto} />
<Spoiler title="USACO Standing Out using Suffix Automata">
@ -202,7 +200,7 @@ Naively, this would take up $O(N^2)$ memory, but *path compression* enables it t
### Problems
<Problems problems={metadata.problems.tree} />
<Problems problems={problems.tree} />
### Generate Suffix Array from Suffix Tree

View file

@ -10,12 +10,10 @@ frequency: 2
import { Problem } from "../models";
export const metadata = {
problems: {
export const problems = {
treeRot: [
new Problem("POI", "Tree Rotations 2", "https://szkopul.edu.pl/problemset/problem/b0BM0al2crQBt6zovEtJfOc6/site/?key=statement", "Normal", false, [], ""),
]
}
};
## Merging
@ -24,7 +22,7 @@ export const metadata = {
## Merging (Arbitrary Keys)
<Problems problems={metadata.problems.treeRot} />
<Problems problems={problems.treeRot} />
<Spoiler title="Tree Rotations 2 Solution">

View file

@ -45,6 +45,7 @@ const MODULE_ORDERING: {[key in SectionID]: Category[]} = {
"fast-io",
"debugging",
"cpp-tips",
"lambda",
]
},
{
@ -94,18 +95,23 @@ const MODULE_ORDERING: {[key in SectionID]: Category[]} = {
]
},
{
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",
]
},
{
@ -113,14 +119,6 @@ const MODULE_ORDERING: {[key in SectionID]: Category[]} = {
items: [
"intro-ordered",
"custom-cpp-stl",
"harder-ordered",
]
},
{
name: "Stacks & Queues",
items: [
"stacks-queues",
"sliding",
]
},
{
@ -133,6 +131,14 @@ const MODULE_ORDERING: {[key in SectionID]: Category[]} = {
},
],
"gold": [
{
name: "Data Structures",
items: [
"stacks",
"sliding",
"queues",
]
},
{
name: "Dynamic Programming",
items: [
@ -304,3 +310,15 @@ SECTIONS.forEach(section => {
});
export { moduleIDToSectionMap };
let moduleIDToURLMap: {[key: string]: string} = {};
SECTIONS.forEach(section => {
MODULE_ORDERING[section].forEach(category => {
category.items.forEach(moduleID => {
moduleIDToURLMap[moduleID] = `/${section}/${moduleID}`;
})
});
});
export { moduleIDToURLMap };

View file

@ -196,41 +196,39 @@ prerequisites:
import { Problem } from '../models';
export const metadata = {
problems: {
standard: [
new Problem('YS', 'Associative Array', 'associative_array', 'Intro'),
new Problem('CSES', 'Distinct Numbers', '1621', 'Intro'),
new Problem(
'CSES',
'Sum of Two Values',
'1640',
'Intro',
false,
[],
'Can be solved without sets.'
),
new Problem('CSES', 'Concert Tickets', '1091', 'Easy', false, [
'iterators',
]),
new Problem('CSES', 'Towers', '1073', 'Easy', false, [
'multiset',
'greedy',
]),
new Problem('CSES', 'Traffic Lights', '1163', 'Normal', false, ['set']),
new Problem('CSES', 'Room Allocation', '1164', 'Normal', false, [
'multiset',
'greedy',
]),
],
},
export const problems = {
standard: [
new Problem('YS', 'Associative Array', 'associative_array', 'Intro'),
new Problem('CSES', 'Distinct Numbers', '1621', 'Intro'),
new Problem(
'CSES',
'Sum of Two Values',
'1640',
'Intro',
false,
[],
'Can be solved without sets.'
),
new Problem('CSES', 'Concert Tickets', '1091', 'Easy', false, [
'iterators',
]),
new Problem('CSES', 'Towers', '1073', 'Easy', false, [
'multiset',
'greedy',
]),
new Problem('CSES', 'Traffic Lights', '1163', 'Normal', false, ['set']),
new Problem('CSES', 'Room Allocation', '1164', 'Normal', false, [
'multiset',
'greedy',
]),
],
};
## Standard
Do roughly the first half of the Sorting and Searching section in the [CSES Problem Set](https://cses.fi/problemset/).
<Problems problems={metadata.problems.standard} />
<Problems problems={problems.standard} />
```
### Resource Lists

View file

@ -1,6 +1,8 @@
import { SECTIONS } from './content/ordering';
const toString = require('mdast-util-to-string');
const mdastToString = require('mdast-util-to-string');
const Slugger = require('github-slugger');
const Problem = require('./src/models/problem').Problem; // needed to eval export
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions;
@ -83,6 +85,19 @@ exports.createSchemaCustomization = ({ actions }) => {
java: [Heading]
py: [Heading]
}
type Problem {
source: String!
name: String!
id: String!
difficulty: String
starred: Boolean
tags: [String]
sketch: String
url: String
isIntro: Boolean
uniqueID: String
}
`;
createTypes(typeDefs);
};
@ -118,8 +133,8 @@ exports.createResolvers = ({ createResolvers }) => {
if (node.type === 'heading') {
let val = {
depth: node.depth,
value: toString(node),
slug: slugger.slug(toString(node)),
value: mdastToString(node),
slug: slugger.slug(mdastToString(node)),
};
if (cppCt === 0 && javaCt === 0 && pyCt === 0) {
cpp.push(val);
@ -143,6 +158,29 @@ exports.createResolvers = ({ createResolvers }) => {
};
},
},
problems: {
type: `[Problem]`,
async resolve(source, args, context, info) {
const { resolve } = info.schema.getType('Mdx').getFields().mdxAST;
let mdast = await resolve(source, args, context, {
fieldName: 'mdast',
});
let problems = [];
mdast.children.forEach(node => {
if (
node.type === 'export' &&
node.value.includes('export const problems =')
) {
let str = node.value.replace('export ', '') + '; problems';
let res = eval(str);
Object.keys(res).forEach(k => {
problems.push(...res[k]);
});
}
});
return problems;
},
},
},
};
createResolvers(resolvers);

View file

@ -5,6 +5,7 @@
"version": "0.1.0",
"author": "Nathan Wang <nathan.r.wang@gmail.com>",
"dependencies": {
"@babel/core": "^7.10.5",
"@mapbox/rehype-prism": "^0.5.0",
"@mdx-js/mdx": "^1.6.6",
"@mdx-js/react": "^1.6.6",

View file

@ -0,0 +1,65 @@
import * as React from 'react';
import { Link } from 'gatsby';
type ActiveItemStatus = 'Solving' | 'Skipped' | 'In Progress';
export type ActiveItem = {
label: string;
status: ActiveItemStatus;
url: string;
};
const statusClasses: { [key in ActiveItemStatus]: string } = {
Solving: 'bg-yellow-100 text-yellow-800',
Skipped: 'bg-gray-100 text-gray-800',
'In Progress': 'bg-green-100 text-green-800',
};
export default function ActiveItems({
type,
items,
}: {
type: 'problems' | 'modules';
items: ActiveItem[];
}) {
return (
<div className="bg-white shadow sm:rounded-lg mb-8">
<div className="px-4 py-5 sm:p-6">
<h3 className="text-lg leading-6 font-medium text-gray-900">
Active {type === 'problems' ? 'Problems' : 'Modules'}
</h3>
<div className="mt-4 text-gray-500">
{items.map((item, idx) => (
<p className={idx === 0 ? '' : 'mt-2'}>
<Link
to={item.url}
className="font-medium text-blue-600 hover:text-blue-500 transition ease-in-out duration-150"
>
{item.label}
<span
className={
'ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium leading-4 ' +
statusClasses[item.status]
}
>
{item.status}
</span>
</Link>
</p>
))}
{/*<p>*/}
{/* <a*/}
{/* href="#"*/}
{/* className="inline-flex items-center font-medium text-blue-600 hover:text-blue-500 transition ease-in-out duration-150"*/}
{/* >*/}
{/* Longest Common Subsequence*/}
{/* <span className="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium leading-4 bg-gray-100 text-gray-800">*/}
{/* Skipped*/}
{/* </span>*/}
{/* </a>*/}
{/*</p>*/}
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,150 @@
import * as React from 'react';
// @ts-ignore
import logo from '../../assets/logo.svg';
// @ts-ignore
import logoSquare from '../../assets/logo-square.png';
import { useState } from 'react';
import { SECTION_LABELS, SECTIONS } from '../../../content/ordering';
import { Link } from 'gatsby';
export default function DashboardNav() {
const [isMobileNavOpen, setIsMobileNavOpen] = useState(false);
const links = [
{
label: 'Dashboard',
url: '/dashboard',
},
...SECTIONS.map(section => ({
label: SECTION_LABELS[section],
url: `/${section}`,
})),
];
return (
<nav className="bg-white shadow">
<div className="max-w-7xl mx-auto px-2 sm:px-4 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex px-2 lg:px-0">
<Link to="/" className="flex-shrink-0 flex items-center">
{/*<img*/}
{/* className="block sm:hidden h-8 w-auto"*/}
{/* src={logoSquare}*/}
{/* alt="USACO Guide"*/}
{/*/>*/}
{/*<img*/}
{/* className="hidden sm:block h-12 w-auto"*/}
{/* src={logo}*/}
{/* alt="USACO Guide"*/}
{/*/>*/}
<img className="block h-12 w-auto" src={logo} alt="USACO Guide" />
</Link>
<div className="hidden lg:ml-6 xl:ml-12 lg:flex space-x-8">
{links.map((link, idx) => (
<Link
key={link.url}
to={link.url}
getProps={({ isCurrent }) => ({
className: isCurrent
? 'inline-flex items-center px-1 pt-1 border-b-2 border-blue-500 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-blue-700 transition duration-150 ease-in-out'
: 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out',
})}
>
{link.label}
</Link>
))}
</div>
</div>
<div className="flex-1 flex items-center justify-center px-2 md:px-0 lg:ml-6 lg:justify-end">
{/*<div className="max-w-lg w-full lg:max-w-xs">*/}
{/* <label htmlFor="search" className="sr-only">*/}
{/* Search*/}
{/* </label>*/}
{/* <div className="relative">*/}
{/* <div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">*/}
{/* <svg*/}
{/* className="h-5 w-5 text-gray-400"*/}
{/* fill="currentColor"*/}
{/* viewBox="0 0 20 20"*/}
{/* >*/}
{/* <path*/}
{/* fillRule="evenodd"*/}
{/* d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"*/}
{/* clipRule="evenodd"*/}
{/* />*/}
{/* </svg>*/}
{/* </div>*/}
{/* <input*/}
{/* id="search"*/}
{/* className="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:border-blue-300 focus:shadow-outline-blue sm:text-sm transition duration-150 ease-in-out"*/}
{/* placeholder="Search"*/}
{/* type="search"*/}
{/* />*/}
{/* </div>*/}
{/*</div>*/}
</div>
<div className="flex items-center lg:hidden">
{/* Mobile menu button */}
<button
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out"
aria-label="Main menu"
aria-expanded="false"
onClick={() => setIsMobileNavOpen(!isMobileNavOpen)}
>
{/* Icon when menu is closed. */}
{/* Menu open: "hidden", Menu closed: "block" */}
<svg
className={`${isMobileNavOpen ? 'hidden' : 'block'} h-6 w-6`}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
{/* Icon when menu is open. */}
{/* Menu open: "block", Menu closed: "hidden" */}
<svg
className={`${isMobileNavOpen ? 'block' : 'hidden'} h-6 w-6`}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
</div>
</div>
{/*
Mobile menu, toggle classes based on menu state.
Menu open: "block", Menu closed: "hidden"
*/}
<div className={`${isMobileNavOpen ? 'block' : 'hidden'} lg:hidden`}>
<div className="pt-2 pb-3 space-y-1">
{links.map((link, idx) => (
<Link
key={link.url}
to={link.url}
getProps={({ isCurrent }) => ({
className: isCurrent
? 'block pl-3 pr-4 py-2 border-l-4 border-indigo-500 text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out'
: 'block pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out',
})}
>
{link.label}
</Link>
))}
</div>
</div>
</nav>
);
}

View file

@ -1,25 +1,25 @@
import * as React from 'react';
const ProgressBar = ({ title }) => {
const ProgressBar = ({ text, green, yellow, blue }) => {
return (
<div className="relative">
<div className="overflow-hidden h-4 text-xs flex rounded-full bg-gray-200">
<div className="overflow-hidden h-4 text-xs flex bg-gray-200">
<div
style={{ width: '45%' }}
style={{ width: `${green}%` }}
className="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-green-500"
/>
<div
style={{ width: '10%' }}
style={{ width: `${yellow}%` }}
className="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-yellow-300"
/>
<div
style={{ width: '5%' }}
style={{ width: `${blue}%` }}
className="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-blue-500"
/>
</div>
<div className="text-right">
<span className="text-sm font-semibold inline-block text-gray-800">
107 total modules
{text}
</span>
</div>
</div>
@ -39,36 +39,47 @@ const FancyNumber = ({ number, text, textColor, bgColor }) => (
</div>
);
export default function SectionProgress() {
export default function DashboardProgress({
completed,
inProgress,
skipped,
notStarted,
total,
}) {
return (
<div>
<div className="grid grid-cols-4 gap-2 mb-4">
<FancyNumber
number="12"
number={completed}
text="Completed"
textColor="text-green-800"
bgColor="bg-green-100"
/>
<FancyNumber
number="3"
number={inProgress}
text="In Progress"
textColor="text-yellow-800"
bgColor="bg-yellow-100"
/>
<FancyNumber
number="1"
number={skipped}
text="Skipped"
textColor="text-blue-800"
bgColor="bg-blue-50"
/>
<FancyNumber
number="8"
number={notStarted}
text="Not Started"
textColor="text-gray-800"
bgColor="bg-gray-100"
/>
</div>
<ProgressBar title="Modules" />
<ProgressBar
green={(completed / total) * 100}
yellow={(inProgress / total) * 100}
blue={(skipped / total) * 100}
text={`${total} total`}
/>
</div>
);
}

View file

@ -0,0 +1,43 @@
import { Link } from 'gatsby';
import * as React from 'react';
export default function WelcomeBackBanner({
lastViewedModuleURL,
lastViewedModuleLabel,
}) {
return (
<div className="bg-blue-700 shadow hover:shadow-lg transition duration-150 ease-in-out lg:rounded-lg w-full">
<Link
className="p-8 block sm:flex sm:items-center sm:justify-between"
to={lastViewedModuleURL || '/intro/using-this-guide'}
>
<div>
<h3 className="text-2xl leading-7 font-medium text-white">
{lastViewedModuleURL
? 'Welcome Back!'
: 'Welcome to the USACO Guide!'}
</h3>
<div className="mt-2 leading-5 text-teal-200">
<p>
{lastViewedModuleURL
? `Pick up where you left off. Your last viewed module was ${lastViewedModuleLabel}.`
: `Get started on the first module, "Using This Guide."`}
</p>
</div>
</div>
<div className="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center lg:mr-2">
<span className="inline-flex rounded-md shadow-sm">
<button
type="button"
className="inline-flex items-center px-4 lg:px-8 py-2 lg:py-3 border border-transparent lg:text-lg font-medium rounded-md text-white bg-blue-800 hover:bg-blue-600 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150"
>
{lastViewedModuleURL
? `Continue: ${lastViewedModuleLabel}`
: `Get Started: Using This Guide!`}
</button>
</span>
</div>
</Link>
</div>
);
}

View file

@ -77,7 +77,7 @@ const Breadcrumbs = () => {
return (
<nav className="flex flex-wrap items-center text-sm leading-loose font-medium">
<Link
to="/"
to="/dashboard"
className="text-gray-500 hover:text-gray-700 transition duration-150 ease-in-out"
>
Home

View file

@ -146,10 +146,14 @@ export function ProblemComponent(props: ProblemComponentProps) {
Insane: 'bg-red-100 text-red-800',
};
const [showTags, setShowTags] = React.useState(false);
const [isActive, setIsActive] = React.useState(false);
const { problem } = props;
const id = `problem-${problem.uniqueID}`;
React.useEffect(() => {
setIsActive(window && window.location && window.location.hash === '#' + id);
}, []);
return (
<tr>
<tr id={id} style={isActive ? { backgroundColor: '#FDFDEA' } : null}>
<td className="pl-4 md:pl-6 whitespace-no-wrap text-sm text-gray-500 font-medium">
<div
style={{ height: '1.25rem' }}

View file

@ -24,6 +24,9 @@ const UserDataContext = createContext<{
problem: Problem,
status: ProblemProgress
) => void;
lastViewedModule: string;
setLastViewedModule: (moduleID: string) => void;
}>({
lang: 'showAll',
setLang: null,
@ -31,6 +34,8 @@ const UserDataContext = createContext<{
setModuleProgress: null,
userProgressOnProblems: null,
setUserProgressOnProblems: null,
lastViewedModule: null,
setLastViewedModule: null,
});
const langKey = 'guide:userData:lang';
@ -70,6 +75,18 @@ const getProblemStatusFromStorage = () => {
return v || {};
};
const lastViewedModuleKey = 'guide:userData:lastViewedModule';
const getLastViewedModuleFromStorage = () => {
let stickyValue = window.localStorage.getItem(lastViewedModuleKey);
let v = null;
try {
v = JSON.parse(stickyValue);
} catch (e) {
console.error("Couldn't parse last viewed module", e);
}
return v || null;
};
export const UserDataProvider = ({ children }) => {
const [lang, setLang] = useState<UserLang>('showAll');
const [userProgress, setUserProgress] = useState<{
@ -78,44 +95,57 @@ export const UserDataProvider = ({ children }) => {
const [problemStatus, setProblemStatus] = useState<{
[key: string]: ProblemProgress;
}>({});
const [lastViewedModule, setLastViewedModule] = useState<string>(null);
React.useEffect(() => {
setLang(getLangFromStorage());
setUserProgress(getProgressFromStorage());
setProblemStatus(getProblemStatusFromStorage());
setLastViewedModule(getLastViewedModuleFromStorage());
}, []);
const userData = React.useMemo(
() => ({
lang: lang as UserLang,
setLang: lang => {
window.localStorage.setItem(langKey, JSON.stringify(lang));
setLang(lang);
},
userProgressOnModules: userProgress,
setModuleProgress: (moduleID: string, progress: ModuleProgress) => {
const newProgress = {
...getProgressFromStorage(),
[moduleID]: progress,
};
window.localStorage.setItem(progressKey, JSON.stringify(newProgress));
setUserProgress(newProgress);
},
userProgressOnProblems: problemStatus,
setUserProgressOnProblems: (problem, status) => {
const newStatus = {
...getProblemStatusFromStorage(),
[problem.uniqueID]: status,
};
window.localStorage.setItem(
problemStatusKey,
JSON.stringify(newStatus)
);
setProblemStatus(newStatus);
},
lastViewedModule,
setLastViewedModule: moduleID => {
window.localStorage.setItem(
lastViewedModuleKey,
JSON.stringify(moduleID)
);
setLastViewedModule(moduleID);
},
}),
[lang, userProgress, problemStatus, lastViewedModule]
);
return (
<UserDataContext.Provider
value={{
lang: lang as UserLang,
setLang: lang => {
window.localStorage.setItem(langKey, JSON.stringify(lang));
setLang(lang);
},
userProgressOnModules: userProgress,
setModuleProgress: (moduleID: string, progress: ModuleProgress) => {
const newProgress = {
...getProgressFromStorage(),
[moduleID]: progress,
};
window.localStorage.setItem(progressKey, JSON.stringify(newProgress));
setUserProgress(newProgress);
},
userProgressOnProblems: problemStatus,
setUserProgressOnProblems: (problem, status) => {
const newStatus = {
...getProblemStatusFromStorage(),
[problem.uniqueID]: status,
};
window.localStorage.setItem(
problemStatusKey,
JSON.stringify(newStatus)
);
setProblemStatus(newStatus);
},
}}
>
<UserDataContext.Provider value={userData}>
{children}
</UserDataContext.Provider>
);

View file

@ -1,379 +1,187 @@
import * as React from 'react';
import { Link, PageProps } from 'gatsby';
import { graphql, Link, PageProps } from 'gatsby';
import Layout from '../components/layout';
import SEO from '../components/seo';
import { useState } from 'react';
// @ts-ignore
import logo from '../assets/logo.svg';
// @ts-ignore
import logoSquare from '../assets/logo-square.png';
import SectionProgress from '../components/Dashboard/SectionProgress';
import DashboardProgress from '../components/Dashboard/DashboardProgress';
import SectionProgressBar from '../components/Dashboard/SectionProgressBar';
import UserDataContext from '../context/UserDataContext';
import WelcomeBackBanner from '../components/Dashboard/WelcomeBackBanner';
import {
moduleIDToSectionMap,
moduleIDToURLMap,
SECTION_LABELS,
} from '../../content/ordering';
import DashboardNav from '../components/Dashboard/DashboardNav';
import ActiveItems, { ActiveItem } from '../components/Dashboard/ActiveItems';
const getProgressInfo = (
keys: string[],
data: { [key: string]: string },
completedValues: string[],
inProgressValues: string[],
skippedValues: string[],
notStartedValues: string[]
) => {
let res = {
completed: 0,
inProgress: 0,
skipped: 0,
notStarted: 0,
};
for (let key of keys) {
if (!(key in data)) res.notStarted++;
else if (completedValues.includes(data[key])) res.completed++;
else if (inProgressValues.includes(data[key])) res.inProgress++;
else if (skippedValues.includes(data[key])) res.skipped++;
else if (notStartedValues.includes(data[key])) res.notStarted++;
}
return res;
};
export default function DashboardPage(props: PageProps) {
const [isMobileNavOpen, setIsMobileNavOpen] = useState(false);
const { modules } = props.data as any;
const moduleIDToName = modules.edges.reduce((acc, cur) => {
acc[cur.node.frontmatter.id] = cur.node.frontmatter.title;
return acc;
}, {});
const problemIDMap = modules.edges.reduce((acc, cur) => {
cur.node.problems.forEach(problem => {
acc[problem.uniqueID] = {
label: `${problem.source}: ${problem.name}`,
url: `${moduleIDToURLMap[cur.node.frontmatter.id]}/#problem-${
problem.uniqueID
}`,
starred: problem.starred,
};
});
return acc;
}, {});
const {
lastViewedModule: lastViewedModuleID,
userProgressOnModules,
userProgressOnProblems,
} = React.useContext(UserDataContext);
const lastViewedModuleURL = moduleIDToURLMap[lastViewedModuleID];
const activeModules: ActiveItem[] = React.useMemo(() => {
return Object.keys(userProgressOnModules)
.filter(
x =>
userProgressOnModules[x] === 'Reading' ||
userProgressOnModules[x] === 'Practicing' ||
userProgressOnModules[x] === 'Skipped'
)
.map(x => ({
label: `${SECTION_LABELS[moduleIDToSectionMap[x]]}: ${
moduleIDToName[x]
}`,
url: moduleIDToURLMap[x],
status:
userProgressOnModules[x] === 'Skipped' ? 'Skipped' : 'In Progress',
}));
}, [userProgressOnModules]);
const activeProblems: ActiveItem[] = React.useMemo(() => {
return Object.keys(userProgressOnProblems)
.filter(
x =>
userProgressOnProblems[x] === 'Solving' ||
userProgressOnProblems[x] === 'Skipped'
)
.map(x => ({
...problemIDMap[x],
status: userProgressOnProblems[x] as 'Solving' | 'Skipped',
}));
}, [userProgressOnProblems]);
let allModulesProgressInfo = getProgressInfo(
Object.keys(moduleIDToName),
userProgressOnModules,
['Complete'],
['Reading', 'Practicing'],
['Skipped'],
['Not Started']
);
const allProblemIDs = Object.keys(problemIDMap);
// const allStarredProblemIDs = allProblemIDs.filter(
// x => problemIDMap[x].starred
// );
const allProblemsProgressInfo = getProgressInfo(
allProblemIDs,
userProgressOnProblems,
['Solved'],
['Solving'],
['Skipped'],
['Not Attempted']
);
// const allStarredProblemsProgressInfo = getProgressInfo(
// allStarredProblemIDs,
// userProgressOnProblems,
// ['Solved'],
// ['Solving'],
// ['Skipped'],
// ['Not Attempted']
// );
return (
<Layout>
<SEO title="Syllabus" />
<SEO title="Dashboard" />
<div className="min-h-screen bg-gray-100">
<nav className="bg-white shadow">
<div className="max-w-7xl mx-auto px-2 sm:px-4 lg:px-8">
<div className="flex justify-between h-16">
<div className="flex px-2 lg:px-0">
<div className="flex-shrink-0 flex items-center">
<img
className="block sm:hidden h-8 w-auto"
src={logoSquare}
alt="USACO Guide"
/>
<img
className="hidden sm:block h-12 w-auto"
src={logo}
alt="USACO Guide"
/>
</div>
<div className="hidden lg:ml-6 xl:ml-12 lg:flex">
<a
href="#"
className="inline-flex items-center px-1 pt-1 border-b-2 border-indigo-500 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out"
>
Dashboard
</a>
<a
href="#"
className="ml-8 inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out"
>
Intro
</a>
<a
href="#"
className="ml-8 inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out"
>
Bronze
</a>
<a
href="#"
className="ml-8 inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out"
>
Silver
</a>
<a
href="#"
className="ml-8 inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out"
>
Gold
</a>
<a
href="#"
className="ml-8 inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out"
>
Plat
</a>
<a
href="#"
className="ml-8 inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out"
>
Advanced
</a>
</div>
</div>
<div className="flex-1 flex items-center justify-center px-2 md:px-0 lg:ml-6 lg:justify-end">
<div className="max-w-lg w-full lg:max-w-xs">
<label htmlFor="search" className="sr-only">
Search
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg
className="h-5 w-5 text-gray-400"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
fillRule="evenodd"
d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
clipRule="evenodd"
/>
</svg>
</div>
<input
id="search"
className="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:border-blue-300 focus:shadow-outline-blue sm:text-sm transition duration-150 ease-in-out"
placeholder="Search"
type="search"
/>
</div>
</div>
</div>
<div className="flex items-center lg:hidden">
{/* Mobile menu button */}
<button
className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 focus:text-gray-500 transition duration-150 ease-in-out"
aria-label="Main menu"
aria-expanded="false"
>
{/* Icon when menu is closed. */}
{/* Menu open: "hidden", Menu closed: "block" */}
<svg
className="block h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
{/* Icon when menu is open. */}
{/* Menu open: "block", Menu closed: "hidden" */}
<svg
className="hidden h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
</div>
</div>
{/*
Mobile menu, toggle classes based on menu state.
<DashboardNav />
Menu open: "block", Menu closed: "hidden"
*/}
<div className="hidden lg:hidden">
<div className="pt-2 pb-3">
<a
href="#"
className="block pl-3 pr-4 py-2 border-l-4 border-indigo-500 text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out"
>
Dashboard
</a>
<a
href="#"
className="mt-1 block pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out"
>
Team
</a>
<a
href="#"
className="mt-1 block pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out"
>
Projects
</a>
<a
href="#"
className="mt-1 block pl-3 pr-4 py-2 border-l-4 border-transparent text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out"
>
Calendar
</a>
</div>
<div className="pt-4 pb-3 border-t border-gray-200">
<div className="flex items-center px-4">
<div className="flex-shrink-0">
<img
className="h-10 w-10 rounded-full"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt=""
/>
</div>
<div className="ml-3">
<div className="text-base font-medium leading-6 text-gray-800">
Tom Cook
</div>
<div className="text-sm font-medium leading-5 text-gray-500">
tom@example.com
</div>
</div>
</div>
<div className="mt-3">
<a
href="#"
className="block px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100 focus:outline-none focus:text-gray-800 focus:bg-gray-100 transition duration-150 ease-in-out"
>
Your Profile
</a>
<a
href="#"
className="mt-1 block px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100 focus:outline-none focus:text-gray-800 focus:bg-gray-100 transition duration-150 ease-in-out"
>
Settings
</a>
<a
href="#"
className="mt-1 block px-4 py-2 text-base font-medium text-gray-500 hover:text-gray-800 hover:bg-gray-100 focus:outline-none focus:text-gray-800 focus:bg-gray-100 transition duration-150 ease-in-out"
>
Sign out
</a>
</div>
</div>
</div>
</nav>
<main className="pt-4 pb-12">
<main className="pb-12">
<div className="max-w-7xl mx-auto mb-4">
<div className="flex overflow-x-auto px-4 sm:px-6 lg:px-8 py-6">
{/*<div className="bg-white shadow sm:rounded-lg w-full max-w-sm">*/}
{/* <div className="px-4 py-5 sm:p-6">*/}
{/* <h3 className="text-lg leading-6 font-medium text-gray-900">*/}
{/* Welcome to the USACO Guide!*/}
{/* </h3>*/}
{/* <div className="mt-2 max-w-xl text-sm leading-5 text-gray-500">*/}
{/* <p>*/}
{/* Get started on the first module, "Using this Guide."*/}
{/* </p>*/}
{/* </div>*/}
{/* <div className="mt-3 text-sm leading-5">*/}
{/* <a*/}
{/* href="#"*/}
{/* className="font-medium text-blue-600 hover:text-blue-500 transition ease-in-out duration-150"*/}
{/* >*/}
{/* Get Started! &rarr;*/}
{/* </a>*/}
{/* </div>*/}
{/* </div>*/}
{/*</div>*/}
<div className="bg-blue-700 shadow hover:shadow-lg transition duration-150 ease-in-out sm:rounded-lg w-full">
<Link
className="px-4 py-5 sm:p-6 lg:p-8 block sm:flex sm:items-center sm:justify-between"
to="/intro/using-guide"
>
<div>
<h3 className="text-2xl leading-7 font-medium text-white">
Welcome Back!
</h3>
<div className="mt-2 leading-5 text-teal-200">
<p>
Pick up where you left off. Your last viewed module was
Input & Output.
</p>
</div>
</div>
<div className="mt-5 sm:mt-0 sm:ml-6 sm:flex-shrink-0 sm:flex sm:items-center mr-2">
<span className="inline-flex rounded-md shadow-sm">
<button
type="button"
className="inline-flex items-center px-8 py-3 border border-transparent text-lg font-medium rounded-md text-white bg-blue-800 hover:bg-blue-600 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150"
>
Continue: Input & Output
</button>
</span>
</div>
</Link>
</div>
<div className="flex overflow-x-auto lg:px-8 lg:pt-10 pb-6">
<WelcomeBackBanner
lastViewedModuleURL={lastViewedModuleURL}
lastViewedModuleLabel={moduleIDToName[lastViewedModuleID]}
/>
</div>
</div>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 grid grid-cols-2 gap-8">
<div>
<div className="bg-white shadow sm:rounded-lg w-full mb-8">
<div className="px-4 py-5 sm:p-6">
<h3 className="text-lg leading-6 font-medium text-gray-900">
Active Problems
</h3>
<div className="mt-4 max-w-xl text-gray-500">
<p className="mb-2">
<a
href="#"
className="inline-flex items-center font-medium text-blue-600 hover:text-blue-500 transition ease-in-out duration-150"
>
Promotion Counting
<span className="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium leading-4 bg-yellow-100 text-yellow-800">
Solving
</span>
</a>
</p>
<p>
<a
href="#"
className="inline-flex items-center font-medium text-blue-600 hover:text-blue-500 transition ease-in-out duration-150"
>
Longest Common Subsequence
<span className="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium leading-4 bg-gray-100 text-gray-800">
Skipped
</span>
</a>
</p>
</div>
</div>
<div className="max-w-7xl mx-auto sm:px-6 lg:px-8 lg:grid lg:grid-cols-2 lg:gap-8">
{activeProblems.length > 0 && (
<div>
<ActiveItems type="problems" items={activeProblems} />
</div>
</div>
<div>
<div className="bg-white shadow sm:rounded-lg">
<div className="px-4 py-5 sm:p-6">
<h3 className="text-lg leading-6 font-medium text-gray-900">
Active Modules
</h3>
<div className="mt-3 max-w-xl text-gray-500">
<p className="mb-2">
<a
href="#"
className="inline-flex items-center font-medium text-blue-600 hover:text-blue-500 transition ease-in-out duration-150"
>
Intro: Input & Output
<span className="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium leading-4 bg-green-100 text-green-800">
Practicing
</span>
</a>
</p>
<p>
<a
href="#"
className="inline-flex items-center font-medium text-blue-600 hover:text-blue-500 transition ease-in-out duration-150"
>
Intro: Expected Knowledge
<span className="ml-2 inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium leading-4 bg-gray-100 text-gray-800">
Skipped
</span>
</a>
</p>
</div>
</div>
)}
{activeModules.length > 0 && (
<div>
<ActiveItems type="modules" items={activeModules} />
</div>
</div>
</div>
<header>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-3xl font-bold leading-tight text-gray-900">
Announcements
</h1>
</div>
</header>
<div className="max-w-7xl mx-auto mb-8">
<div className="flex overflow-x-auto px-4 sm:px-6 lg:px-8 py-4 grid grid-cols-2 gap-8">
<div className="bg-white shadow hover:shadow-lg transition duration-150 ease-in-out sm:rounded-lg">
<div className="px-4 py-5 sm:p-6 cursor-pointer">
<p className="text-sm leading-5 text-gray-500">
<time dateTime="2020-07-18">July 18, 2020</time>
</p>
<h3 className="mt-2 text-xl leading-7 font-semibold text-gray-900">
Looking for Contributors!
</h3>
<p className="mt-3 text-base leading-6 text-gray-500">
Welcome to the USACO Guide! We're still in pre-release mode,
so things may be a bit rough around the edges. Learn more
about what this means, and how you can help contribute!
</p>
<div className="mt-3">
<span className="text-base leading-6 font-semibold text-indigo-600 hover:text-indigo-500 transition ease-in-out duration-150">
Continue Reading
</span>
</div>
</div>
</div>
</div>
)}
</div>
{/*<header>*/}
{/* <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">*/}
{/* <h1 className="text-3xl font-bold leading-tight text-gray-900">*/}
{/* Announcements*/}
{/* </h1>*/}
{/* </div>*/}
{/*</header>*/}
{/*<div className="max-w-7xl mx-auto mb-8">*/}
{/* <div className="flex overflow-x-auto sm:px-6 lg:px-8 py-4 lg:grid lg:grid-cols-2 lg:gap-8">*/}
{/* <div className="bg-white shadow hover:shadow-lg transition duration-150 ease-in-out sm:rounded-lg">*/}
{/* <div className="px-4 py-5 sm:p-6 cursor-pointer">*/}
{/* <p className="text-sm leading-5 text-gray-500">*/}
{/* <time dateTime="2020-07-18">July 18, 2020</time>*/}
{/* </p>*/}
{/* <h3 className="mt-2 text-xl leading-7 font-semibold text-gray-900">*/}
{/* Looking for Contributors!*/}
{/* </h3>*/}
{/* <p className="mt-3 text-base leading-6 text-gray-500">*/}
{/* Welcome to the USACO Guide! We're still in pre-release mode,*/}
{/* so things may be a bit rough around the edges. Learn more*/}
{/* about what this means, and how you can help contribute!*/}
{/* </p>*/}
{/* <div className="mt-3">*/}
{/* <span className="text-base leading-6 font-semibold text-indigo-600 hover:text-indigo-500 transition ease-in-out duration-150">*/}
{/* Continue Reading*/}
{/* </span>*/}
{/* </div>*/}
{/* </div>*/}
{/* </div>*/}
{/* </div>*/}
{/*</div>*/}
<header>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-3xl font-bold leading-tight text-gray-900">
@ -382,45 +190,7 @@ export default function DashboardPage(props: PageProps) {
</div>
</header>
<div className="max-w-7xl mx-auto">
<div className="px-4 sm:px-6 lg:px-8 py-4 grid grid-cols-2 gap-8">
<div className="space-y-8">
<div className="bg-white shadow sm:rounded-lg overflow-hidden row-span-2 flex flex-col">
<div className="px-4 pt-5 sm:px-6 sm:pt-6 pb-4">
<h3 className="text-lg leading-6 font-medium text-gray-900">
🔥 6 Day Streak: Keep it up!
</h3>
<div className="mt-2 max-w-xl text-sm leading-5 text-gray-500">
<p>
You've visited this guide for 6 consecutive days. Enjoy
this cute cow photo as a reward!
</p>
</div>
</div>
<img
className="h-64 w-full object-cover"
src="https://66.media.tumblr.com/709acf5805b63bf412dd5cf8d6e34803/tumblr_oplgjdcYJl1sgqqono1_500.jpg"
alt="Cow"
/>
</div>
<div className="bg-white shadow sm:rounded-lg">
<div className="px-4 py-5 sm:p-6">
<h3 className="text-lg leading-6 font-medium text-gray-900">
Section Breakdown
</h3>
<div className="mt-2 max-w-xl text-sm leading-5 text-gray-500">
<p>Below is your progress on modules for each section.</p>
</div>
<div className="mt-4">
<SectionProgressBar title="Intro" />
<SectionProgressBar title="Bronze" />
<SectionProgressBar title="Silver" />
<SectionProgressBar title="Gold" />
<SectionProgressBar title="Plat" />
<SectionProgressBar title="Advanced" />
</div>
</div>
</div>
</div>
<div className="sm:px-6 lg:px-8 py-4 lg:grid lg:grid-cols-2 lg:gap-8 space-y-8 lg:space-y-0">
<div className="space-y-8">
<div className="bg-white shadow sm:rounded-lg">
<div className="px-4 py-5 sm:p-6">
@ -428,30 +198,77 @@ export default function DashboardPage(props: PageProps) {
All Modules
</h3>
<div className="mt-6">
<SectionProgress />
</div>
</div>
</div>
<div className="bg-white shadow sm:rounded-lg">
<div className="px-4 py-5 sm:p-6">
<h3 className="text-lg leading-6 font-medium text-gray-900">
All Starred Problems
</h3>
<div className="mt-6">
<SectionProgress />
<DashboardProgress
{...allModulesProgressInfo}
total={Object.keys(moduleIDToName).length}
/>
</div>
</div>
</div>
{/*<div className="bg-white shadow sm:rounded-lg">*/}
{/* <div className="px-4 py-5 sm:p-6">*/}
{/* <h3 className="text-lg leading-6 font-medium text-gray-900">*/}
{/* All Starred Problems*/}
{/* </h3>*/}
{/* <div className="mt-6">*/}
{/* <DashboardProgress*/}
{/* {...allStarredProblemsProgressInfo}*/}
{/* total={Object.keys(allStarredProblemIDs).length}*/}
{/* />*/}
{/* </div>*/}
{/* </div>*/}
{/*</div>*/}
</div>
<div className="space-y-8">
<div className="bg-white shadow sm:rounded-lg order-6">
<div className="px-4 py-5 sm:p-6">
<h3 className="text-lg leading-6 font-medium text-gray-900">
All Problems
</h3>
<div className="mt-6">
<SectionProgress />
<DashboardProgress
{...allProblemsProgressInfo}
total={Object.keys(allProblemIDs).length}
/>
</div>
</div>
</div>
{/*<div className="bg-white shadow sm:rounded-lg overflow-hidden row-span-2 flex flex-col">*/}
{/* <div className="px-4 pt-5 sm:px-6 sm:pt-6 pb-4">*/}
{/* <h3 className="text-lg leading-6 font-medium text-gray-900">*/}
{/* 🔥 6 Day Streak: Keep it up!*/}
{/* </h3>*/}
{/* <div className="mt-2 max-w-xl text-sm leading-5 text-gray-500">*/}
{/* <p>*/}
{/* You've visited this guide for 6 consecutive days. Enjoy*/}
{/* this cute cow photo as a reward!*/}
{/* </p>*/}
{/* </div>*/}
{/* </div>*/}
{/* <img*/}
{/* className="h-64 w-full object-cover"*/}
{/* src="https://66.media.tumblr.com/709acf5805b63bf412dd5cf8d6e34803/tumblr_oplgjdcYJl1sgqqono1_500.jpg"*/}
{/* alt="Cow"*/}
{/* />*/}
{/*</div>*/}
{/*<div className="bg-white shadow sm:rounded-lg">*/}
{/* <div className="px-4 py-5 sm:p-6">*/}
{/* <h3 className="text-lg leading-6 font-medium text-gray-900">*/}
{/* Section Breakdown*/}
{/* </h3>*/}
{/* <div className="mt-2 max-w-xl text-sm leading-5 text-gray-500">*/}
{/* <p>Below is your progress on modules for each section.</p>*/}
{/* </div>*/}
{/* <div className="mt-4">*/}
{/* <SectionProgressBar title="Intro" />*/}
{/* <SectionProgressBar title="Bronze" />*/}
{/* <SectionProgressBar title="Silver" />*/}
{/* <SectionProgressBar title="Gold" />*/}
{/* <SectionProgressBar title="Plat" />*/}
{/* <SectionProgressBar title="Advanced" />*/}
{/* </div>*/}
{/* </div>*/}
{/*</div>*/}
</div>
</div>
</div>
@ -460,3 +277,24 @@ export default function DashboardPage(props: PageProps) {
</Layout>
);
}
export const pageQuery = graphql`
query {
modules: allMdx {
edges {
node {
frontmatter {
title
id
}
problems {
uniqueID
source
name
starred
}
}
}
}
}
`;

View file

@ -195,7 +195,7 @@ export default function IndexPage(props: PageProps) {
<div className="mt-5 sm:mt-8 sm:flex sm:justify-center lg:justify-start">
<div className="rounded-md shadow">
<Link
to="/intro"
to="/dashboard"
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-blue-600 hover:bg-blue-500 focus:outline-none focus:border-blue-700 focus:shadow-outline-blue transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10"
>
View Guide
@ -486,7 +486,7 @@ export default function IndexPage(props: PageProps) {
<div className="mt-8 flex justify-center">
<div className="rounded-md shadow">
<Link
to="/intro"
to="/dashboard"
className="w-full flex items-center justify-center px-8 py-3 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-blue-600 hover:bg-blue-500 focus:outline-none focus:border-blue-700 focus:shadow-outline-blue transition duration-150 ease-in-out md:py-4 md:text-lg md:px-10"
>
View Guide

View file

@ -7,11 +7,17 @@ import { SECTION_LABELS } from '../../content/ordering';
import { graphqlToModuleInfo } from '../utils';
import SEO from '../components/seo';
import ModuleLayout from '../components/ModuleLayout/ModuleLayout';
import { useContext } from 'react';
import UserDataContext from '../context/UserDataContext';
export default function Template(props) {
const { mdx } = props.data; // data.markdownRemark holds your post data
const { body } = mdx;
const module = React.useMemo(() => graphqlToModuleInfo(mdx), [mdx]);
const { setLastViewedModule } = useContext(UserDataContext);
React.useEffect(() => {
setLastViewedModule(module.id);
}, []);
return (
<Layout>
<SEO

Some files were not shown because too many files have changed in this diff Show more