update resources / problem formatting, bronze - gold

This commit is contained in:
Benjamin Qi 2020-07-13 13:40:05 -04:00
parent c8a0012d0b
commit 4fc9ae92b1
13 changed files with 233 additions and 166 deletions

View file

@ -8,7 +8,7 @@ description: Detecting issues within your program and figuring out how to avoid
## General
<resources>
<resource source="Errichto" title="How to test your solution" url="https://www.youtube.com/watch?v=JXTVOyQpSGM" starred> </resource>
<resource source="Errichto" title="Video - How to test your solution" url="https://www.youtube.com/watch?v=JXTVOyQpSGM" starred>using a script to stress test</resource>
<resource source="Errichto" title="Asking for help FAQ" url="https://codeforces.com/blog/entry/64993" starred>some parts from above video</resource>
</resources>

View file

@ -31,12 +31,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, [], ""),
],
permSam: [
new Problem("CSES", "Creating Strings I", "1622", "Intro|Easy", false, [], "all perms of string"),
],
perm: [
new Problem("Bronze", "Livestock Lineup", "965", "Hard", false, ["permutations"], ""), // 91.95
]
}
};
@ -50,11 +44,9 @@ In many problems (especially in Bronze) it suffices to check all possible cases
## Example
### Statement
You are given $N$ $(3 \leq N \leq 5000)$ integer points on the coordinate plane. Find the square of the maximum Euclidean distance (aka length of the straight line) between any two of the points.
#### Input Format
### Input Format
The first line contains an integer $N$.
@ -62,7 +54,7 @@ The second line contains $N$ integers, the $x$-coordinates of the points: $x_1,
The third line contains $N$ integers, the $y$-coordinates of the points: $y_1, y_2, \dots, y_N$ ($-1000 \leq y_i \leq 1000$).
#### Output Format
### Output Format
Print one integer, the square of the maximum Euclidean distance between any two of the points.
@ -97,6 +89,8 @@ for(int i = 0; i < n; i++){ // for each first point
cout << high << endl;
```
<br />
A couple notes:
- First, since we're iterating through all pairs of points, we start the $j$ loop from $j = i+1$ so that point $i$ and point $j$ are never the same point. Furthermore, it makes it so that each pair is only counted once. In this problem, it doesn't matter whether we double-count pairs or whether we allow $i$ and $j$ to be the same point, but in other problems where we're counting something rather than looking at the maximum, it's important to be careful that we don't overcount.
@ -113,103 +107,3 @@ A couple notes:
### Harder
<problems-list problems={metadata.problems.harder} />
## Generating Permutations
<resources>
<resource source="GFG" url="write-a-c-program-to-print-all-permutations-of-a-given-string"> </resource>
</resources>
<problems-list problems={metadata.problems.permSam} />
A **permutation** is a reordering of a list of elements. Some problems will ask for an ordering of elements that satisfies certain conditions. In these problems, if $N \leq 10$, we can probably iterate through all permutations and check each permutation for validity. For a list of $N$ elements, there are $N!$ ways to permute them, and generally we'll need to read through each permutation once to check its validity, for a time complexity of $O(N \cdot N!)$.
### Java
We'll have to implement this ourselves, which is called [Heap's Algorithm](https://en.wikipedia.org/wiki/Heap%27s_algorithm) (no relation to the heap data structure). What's going to be in the check function depends on the problem, but it should verify whether the current permutation satisfies the constraints given in the problem.
As an example, here are the permutations generated by Heap's Algorithm for $[1, 2, 3]$:
$$
[1, 2, 3], [2, 1, 3], [3, 1, 2], [1, 3, 2], [2, 3, 1], [3, 2, 1]
$$
Code for iterating over all permutations is as follows:
```java
// this method is called with k equal to the length of arr
static void generate(int[] arr, int k){
if(k == 1){
check(arr); // check the current permutation for validity
} else {
generate(arr, k-1);
for(int i = 0; i < k-1; i++){
if(k % 2 == 0){
swap(arr, i, k-1);
// swap indices i and k-1 of arr
} else {
swap(arr, 0, k-1);
// swap indices 0 and k-1 of arr
}
generate(arr, k-1);
}
}
}
```
However, the correctness of this code is not immediately apparent, and it does not generate permutations in lexicographical order (but the following does):
```java
import java.util.*;
public class Test {
static boolean[] used;
static ArrayList<Integer> cur = new ArrayList<Integer>();
static int n;
static void gen() {
if (cur.size() == n) {
System.out.println(cur); // print permutation
return;
}
for (int i = 0; i < n; ++i) if (!used[i]) {
used[i] = true; cur.add(i+1);
gen();
used[i] = false; cur.remove(cur.size()-1);
}
}
static void genPerm(int _n) {
n = _n; used = new boolean[n];
gen();
}
public static void main(String[] Args) {
genPerm(5);
}
}
```
### C++
We can just use the `next_permutation()` function. This function takes in a range and modifies it to the next greater permutation. If there is no greater permutation, it returns false. To iterate through all permutations, place it inside a `do-while` loop. We are using a `do-while` loop here instead of a typical `while` loop because a `while` loop would modify the smallest permutation before we got a chance to process it.
```cpp
do {
check(v); // process or check the current permutation for validity
} while(next_permutation(v.begin(), v.end()));
```
Note that this generates the permutations in **lexicographical order**.
<spoiler title="What's lexicographical order?">
Think about how are words ordered in a dictionary. (In fact, this is where the term "lexicographical" comes from.)
In dictionaries, you will see that words beginning with the letter 'a' appears at the very beginning, followed by words beginning with 'b', and so on. If two words have the same starting letter, the second letter is used to compare them; if both the first and second letters are the same, then use the third letter to compare them, and so on until we either reach a letter that is different, or we reach the end of some word (in this case, the shorter word goes first).
Permutations can be placed into lexicographical order in almost the same way. We first group permutations by their first element; if the first element of two permutations are equal, then we compare them by the second element; if the second element is also equal, then we compare by the third element, and so on.
For example, the permutations of 3 elements, in lexicographical order, are [1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], and [3, 2, 1]. Notice that the list starts with permutations beginning with 1 (just like a dictionary that starts with words beginning with 'a'), followed by those beginning with 2 and those beginning with 3. Within the same starting element, the second element is used to make comparisions.
Generally, unless you are specifically asked to find the lexicographically smallest/largest solution, you do not need to worry about whether permutations are being generated in lexicographical order. However, the idea of lexicographical order does appear quite often in programming contest problems, and in a variety of contexts, so it is strongly recommended that you familiarize yourself with its definition.
</spoiler>
### Problems
<problems-list problems={metadata.problems.perm} />

View file

@ -0,0 +1,124 @@
---
id: gen-perm
title: "Generating Permutations"
author: Darren Yao, Sam Zhang
description: "?"
frequency: 4
---
import { Problem } from "../models";
export const metadata = {
problems: {
permSam: [
new Problem("CSES", "Creating Strings I", "1622", "Intro|Easy", false, [], "all perms of string"),
],
perm: [
new Problem("Bronze", "Livestock Lineup", "965", "Hard", false, ["permutations"], ""), // 91.95
]
}
};
<resources>
<resource source="GFG" url="write-a-c-program-to-print-all-permutations-of-a-given-string" title="Printing all Permutations of Given String"> </resource>
</resources>
<problems-list problems={metadata.problems.permSam} />
A **permutation** is a reordering of a list of elements. Some problems will ask for an ordering of elements that satisfies certain conditions. In these problems, if $N \leq 10$, we can probably iterate through all permutations and check each permutation for validity. For a list of $N$ elements, there are $N!$ ways to permute them, and generally we'll need to read through each permutation once to check its validity, for a time complexity of $O(N \cdot N!)$.
### Java
We'll have to implement this ourselves, which is called [Heap's Algorithm](https://en.wikipedia.org/wiki/Heap%27s_algorithm) (no relation to the heap data structure). What's going to be in the check function depends on the problem, but it should verify whether the current permutation satisfies the constraints given in the problem.
As an example, here are the permutations generated by Heap's Algorithm for $[1, 2, 3]$:
$$
[1, 2, 3], [2, 1, 3], [3, 1, 2], [1, 3, 2], [2, 3, 1], [3, 2, 1]
$$
Code for iterating over all permutations is as follows:
```java
// this method is called with k equal to the length of arr
static void generate(int[] arr, int k){
if(k == 1){
check(arr); // check the current permutation for validity
} else {
generate(arr, k-1);
for(int i = 0; i < k-1; i++){
if(k % 2 == 0){
swap(arr, i, k-1);
// swap indices i and k-1 of arr
} else {
swap(arr, 0, k-1);
// swap indices 0 and k-1 of arr
}
generate(arr, k-1);
}
}
}
```
However, the correctness of this code is not immediately apparent, and it does not generate permutations in **lexicographical order** (but the following does):
```java
import java.util.*;
public class Test {
static boolean[] used;
static ArrayList<Integer> cur = new ArrayList<Integer>();
static int n;
static void gen() {
if (cur.size() == n) {
System.out.println(cur); // print permutation
return;
}
for (int i = 0; i < n; ++i) if (!used[i]) {
used[i] = true; cur.add(i+1);
gen();
used[i] = false; cur.remove(cur.size()-1);
}
}
static void genPerm(int _n) {
n = _n; used = new boolean[n];
gen();
}
public static void main(String[] Args) {
genPerm(5);
}
}
```
### C++
We can just use the `next_permutation()` function. This function takes in a range and modifies it to the next greater permutation. If there is no greater permutation, it returns false. To iterate through all permutations, place it inside a `do-while` loop. We are using a `do-while` loop here instead of a typical `while` loop because a `while` loop would modify the smallest permutation before we got a chance to process it.
```cpp
do {
check(v); // process or check the current permutation for validity
} while(next_permutation(v.begin(), v.end()));
```
Note that this generates the permutations in **lexicographical order**.
### What's lexicographical order?
Think about how are words ordered in a dictionary. (In fact, this is where the term "lexicographical" comes from.)
In dictionaries, you will see that words beginning with the letter 'a' appears at the very beginning, followed by words beginning with 'b', and so on. If two words have the same starting letter, the second letter is used to compare them; if both the first and second letters are the same, then use the third letter to compare them, and so on until we either reach a letter that is different, or we reach the end of some word (in this case, the shorter word goes first).
Permutations can be placed into lexicographical order in almost the same way. We first group permutations by their first element; if the first element of two permutations are equal, then we compare them by the second element; if the second element is also equal, then we compare by the third element, and so on.
For example, the permutations of 3 elements, in lexicographical order, are
$$
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1].
$$
Notice that the list starts with permutations beginning with 1 (just like a dictionary that starts with words beginning with 'a'), followed by those beginning with 2 and those beginning with 3. Within the same starting element, the second element is used to make comparisions.
Generally, unless you are specifically asked to find the lexicographically smallest/largest solution, you do not need to worry about whether permutations are being generated in lexicographical order. However, the idea of lexicographical order does appear quite often in programming contest problems, and in a variety of contexts, so it is strongly recommended that you familiarize yourself with its definition.
### Problems
<problems-list problems={metadata.problems.perm} />

View file

@ -13,10 +13,10 @@ import { Problem } from "../models";
export const metadata = {
problems: {
ex: [
new Problem("CF", "Div 2 C - Maximum Median", "contest/1201/problem/C", "Easy", false, [], ""),
new Problem("CF", "Div 2 C - Maximum Median", "contest/1201/problem/C", "Intro|Easy", false, [], ""),
],
usaco: [
new Problem("Silver", "Moo Buzz", "966", "Easy", false, [], "binary search not required"),
new Problem("Silver", "Moo Buzz", "966", "Very Easy", false, [], "binary search not required"),
new Problem("Silver", "Cow Dance Show", "690", "Easy", false, [], "binary search on $K$ and simulate"),
new Problem("Silver", "Convention", "858", "Easy", false, [], "determine whether $M$ buses suffice if every cow waits at most $T$ minutes, use a greedy strategy (applies to next two problems as well)"),
new Problem("Silver", "Angry Cows", "594", "Easy", false, [], "check in $O(N)$ how many haybales you can destroy with fixed radius $R$"),
@ -114,7 +114,9 @@ int main() {
**Constraints:** $1 \leq n \leq 2 \cdot 10^5, 1 \leq k \leq 10^9$ and $n$ is odd.
**Solution:** We first sort the array in ascending order. Then, we binary search for the maximum possible median. We know that the number of operations required to raise the median to $x$ increases monotonically as $x$ increases, so we can use binary search. For a given median value $x$, the number of operations required to raise the median to $x$ is
<spoiler title="Solution">
We first sort the array in ascending order. Then, we binary search for the maximum possible median. We know that the number of operations required to raise the median to $x$ increases monotonically as $x$ increases, so we can use binary search. For a given median value $x$, the number of operations required to raise the median to $x$ is
$$
\sum_{i=(n+1)/2}^{n} \max(0, x - \texttt{arr}[i]).
@ -199,6 +201,8 @@ static boolean check(long x){
}
```
</spoiler>
## USACO Problems
<problems-list problems={metadata.problems.usaco} />

View file

@ -13,10 +13,10 @@ import { Problem } from "../models";
export const metadata = {
problems: {
sample: [
new Problem("CSES", "Building Roads", "1666", "Intro", false, ["DFS"]),
new Problem("CSES", "Building Roads", "1666", "Intro|Very Easy", false, ["DFS"]),
],
tree: [
new Problem("CSES", "Subordinates", "1674", "Intro", false, ["Tree", "DFS"]),
new Problem("CSES", "Subordinates", "1674", "Very Easy", false, ["Tree", "DFS"]),
new Problem("Silver", "Mootube", "788", "Easy", false, ["Tree", "DFS"]),
new Problem("CF", "Journey", "contest/839/problem/C", "Easy", false, ["Tree", "DFS"]),
new Problem("CF", "PolandBall & Forest", "problemset/problem/755/C", "Easy", false, ["Tree", "DFS"]),

View file

@ -43,19 +43,18 @@ export const metadata = {
}
};
## Additional Reading
<resources>
<resource source="IUSACO" title="9 - Greedy Algorithms" starred>Text below is based off this.</resource>
<resource source="CPH" title="6 - Greedy Algorithms" starred></resource>
<resource source="PAPS" title="8 - Greedy Algorithms"></resource>
<resource source="CPC" title="5 - Greedy Algorithms" url="05_greedy_algorithms"></resource>
</resources>
# Greedy
**Greedy** does not refer to a single algorithm, but rather a way of thinking that is applied to problems. There's no one way to do greedy algorithms. Hence, we use a selection of well-known examples to help you understand the greedy paradigm.
Greedy does not refer to a single algorithm, but rather a way of thinking that is applied to problems. There's no one way to do greedy algorithms. Hence, we use a selection of well-known examples to help you understand the greedy paradigm.
Usually, when using a greedy algorithm, there is a **heuristic** or **value function** that determines which choice is considered most optimal. Usually (but not always) some sorting step is involved.
Usually, when using a greedy algorithm, there is a heuristic or value function that determines which choice is considered most optimal. Usually (but not always) some sorting step is involved.
(what's a heuristic or value function?)
## Example: Studying Algorithms
@ -134,7 +133,7 @@ Instead, we can select the event that ends as early as possible. This correctly
In fact, this algorithm always works. A brief explanation of correctness is as follows. If we have two events $E_1$ and $E_2$, with $E_2$ ending later than $E_1$, then it is always optimal to select $E_1$. This is because selecting $E_1$ gives us more choices for future events. If we can select an event to go after $E_2$, then that event can also go after $E_1$, because $E_1$ ends first. Thus, the set of events that can go after $E_2$ is a subset of the events that can go after $E_1$, making $E_1$ the optimal choice.
For the following code, let's say we have the array `events` of events, which each contain a start and an end point. We'll be using the following static class to store each event (a review of the previous chapter!)
For the following code, let's say we have the array `events` of events, which each contain a start and an end point. We'll be using the following static class to store each event:
```java
static class Event implements Comparable<Event>{
@ -181,18 +180,15 @@ The knapsack problem gives a number of items, each having a weight and a value,
Let's take the following example, where we have a maximum capacity of 4:
(table)
<!-- \begin{center}
\begin{tabular}{c c c c}
\toprule
Item & Weight & Value & Value Per Weight \\
\midrule
A & 3 & 18 & 6 \\
B & 2 & 10 & 5 \\
C & 2 & 10 & 5 \\
\bottomrule
\end{tabular}
\end{center} -->
<center>
| Item | Weight | Value | Value Per Weight |
|------|--------|-------|------------------|
| A | 3 | 18 | 6 |
| B | 2 | 10 | 5 |
| C | 2 | 10 | 5 |
</center>
If we use greedy based on highest value first, we choose item A and then we are done, as we don't have remaining weight to fit either of the other two. Using greedy based on value per weight again selects item A and then quits. However, the optimal solution is to select items B and C, as they combined have a higher value than item A alone. In fact, there is no working greedy solution. The solution to this problem uses **dynamic programming**, which is covered in gold.
@ -205,6 +201,6 @@ If we use greedy based on highest value first, we choose item A and then we are
<problems-list problems={metadata.problems.usaco} />
## Other PRoblems
## Other Problems
<problems-list problems={metadata.problems.other} />

View file

@ -177,7 +177,7 @@ 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 problem, 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:
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.

View file

@ -30,15 +30,15 @@ export const metadata = {
new Problem("CSES", "Unordered Coin Change", "1635", "Intro", true, ["DP", "Knapsack"], "dp[first i coins][sum] = number of ways, order of loops is capacity then coins, remember to take MOD after every computation"),
new Problem("CSES", "Ordered Coin Change", "1636", "Intro", true, ["DP", "Knapsack"], "dp[first i coins][sum] = number of ways, order of loops is coins then capacity, remember to take MOD after every computation"),
new Problem("CSES", "Minimum Coins", "1634", "Intro", true, ["DP", "Knapsack"], "dp[first i coins][sum] = minimum number of coins needed"),
new Problem("Atcoder", "Knapsack 2", "https://atcoder.jp/contests/dp/tasks/dp_e", "Easy", false, ["DP", "Knapsack"], "maximum capacity is large, and sum of values is small, so switch the states. dp[first i items][sum of values] = minimum capacity needed to achieve this sum"),
new Problem("AC", "Knapsack 2", "contests/dp/tasks/dp_e", "Easy", false, ["DP", "Knapsack"], "maximum capacity is large, and sum of values is small, so switch the states. dp[first i items][sum of values] = minimum capacity needed to achieve this sum"),
new Problem("Gold", "Fruit Feast", "574", "Easy", false, ["DP", "Knapsack"], "dp[fullness] = whether you can achieve this fullness"),
new Problem("Gold", "Talent Show", "839", "Hard", false, ["DP", "Knapsack", "Binary Search", "Math"], "binary search on optimal ratio, then do knapsack on weight"),
new Problem("CF", "Round Subset", "http://codeforces.com/contest/837/problem/D", "Normal", false, ["DP", "Knapsack"], "dp[i][j][l] -> maximum amount of twos we can collect by checking first i numbers, taking j of them with total power of five equal to l"),
],
pathsGrid: [
new Problem("LC", "Longest Common Subsequence", "https://leetcode.com/problems/longest-common-subsequence/", "Intro", true, ["DP"], "dp[first i characters in first string][first j characters in second string] -> longest common subsequence, transition if s[i] = t[j] for strings s and t"),
new Problem("HackerRank", "Edit Distance", "https://www.hackerrank.com/contests/cse-830-homework-3/challenges/edit-distance", "Intro", true, ["DP"], "dp[first i characters in first string][first j characters in second string] -> edit distance"),
new Problem("Atcoder", "Count Paths", "https://atcoder.jp/contests/dp/tasks/dp_h", "Intro", true, ["DP"], "dp[x][y] = number of paths up to the point (x,y) in grid"),
new Problem("HR", "Edit Distance", "contests/cse-830-homework-3/challenges/edit-distance", "Intro", true, ["DP"], "dp[first i characters in first string][first j characters in second string] -> edit distance"),
new Problem("AC", "Count Paths", "https://atcoder.jp/contests/dp/tasks/dp_h", "Intro", true, ["DP"], "dp[x][y] = number of paths up to the point (x,y) in grid"),
new Problem("Gold", "Cow Checklist", "670", "Easy", false, ["DP"], "dp[visited i Hs][visited j Gs][last cow visited on left/right] -> min energy"),
new Problem("Gold", "Radio Contact", "598", "Easy", false, ["DP"], "dp[up to ith step of Farmer John][up to jth step of bessie] = minimum distance"),
new Problem("Gold", "Why Did The Cow Cross the Road II", "598", "Normal", false, ["DP"], "dp[up to ith field on left side][up to jth field on right side] = maximum number of disjoint crosswalks"),

View file

@ -42,20 +42,16 @@ export const metadata = {
}
};
## Sample Problems
## Binary Indexed Tree
<problems-list problems={metadata.problems.sample} />
## Binary Indexed Tree
A *Binary Indexed Tree* allows you to perform the following tasks in $O(\log N)$ time each on an array of size $N$:
A *Binary Indexed Tree* (aka *Fenwick Tree*) allows you to perform the following tasks in $O(\log N)$ time each on an array of size $N$:
- Update the element at a single position (point).
- Query the sum of a prefix of the array.
Aka *Fenwick Tree*.
### Tutorials
### Resources
<resources>
<resource source="CSA" title="Fenwick Trees" url="fenwick_trees" starred>interactive</resource>
@ -64,18 +60,31 @@ Aka *Fenwick Tree*.
<resource source="TC" title="Binary Indexed Trees" url="binary-indexed-trees"></resource>
</resources>
My implementation can be found [here](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BIT%20(9.2).h), and can compute range sum queries for any number of dimensions.
### Implementations
## Finding K-th Element in BIT?
<resources>
<resource source="CF" title="mouse_wireless - Multi-dimensional BITs with Templates" url="https://codeforces.com/blog/entry/64914" starred></resource>
<resource source="Benq" title="BIT" url="https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/1D%20Range%20Queries%20(9.2)/BIT%20(9.2).h">based off above</resource>
</resources>
## Indexed Set
## Finding $k$-th Element
In the special case where all elements of the array are either zero or one (which is the case for several gold problems), users of C++ will find [indexed set](https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/STL%20(5)/IndexedSet.h) useful. Using this, we can solve "Inversion Counting" in just a few lines (with template). `Tree<int>` behaves mostly the same way as `set<int>` with the additional functions
Suppose that we want a data structure that supports all the operations as a `set` in C++ in addition to the following:
* `order_of_key(x)`: counts the number of elements in the indexed set that are strictly less than `x`.
* `order_of_key(x)`: counts the number of elements in the set that are strictly less than `x`.
* `find_by_order(k)`: similar to `find`, returns the iterator corresponding to the `k`-th lowest element in the set (0-indexed).
See the link for more examples of usage.
### Indexed Set
Luckily, such a built-in data structure already exists in C++.
<resources>
<resource source="CF" url="blog/entry/11080" title="adamant - Policy Based Data Structures" starred> </resource>
<resource source="Benq" url="https://github.com/bqi343/USACO/blob/master/Implementations/content/data-structures/STL%20(5)/IndexedSet.h" title="Indexed Set"></resource>
</resources>
Using this, we can solve "Inversion Counting" in just a few lines (with template).
<spoiler title="INVCNT with Indexed Set">
@ -106,7 +115,16 @@ int main() {
</spoiler>
Note that if it were not the case that all elements of the input array were distinct, then this code would be incorrect since `Tree<int>` would remove duplicates. Instead, we would use an indexed set of pairs (`Tree<pair<int,int>>`), where the first element of each pair would denote the value while the second would denote the array position.
Note that if it were not the case that all elements of the input array were distinct, then this code would be incorrect since `Tree<int>` would remove duplicates. Instead, we would use an indexed set of pairs (`Tree<pair<int,int>>`), where the first element of each pair would denote the value while the second would denote the position of the value in the array.
### Using a BIT
Assumes all updates are in the range $[1,N]$.
<resources>
<resource source="CF" url="blog/entry/11275" title="adamant - About Ordered Set" starred> log N </resource>
<resource source="GFG" url="order-statistic-tree-using-fenwick-tree-bit" title="Order Statistic Tree using BIT"> log^2 N </resource>
</resources>
## Practice Problems

View file

@ -1,4 +1,5 @@
const sources = {
"AC": "https://atcoder.jp/",
"CC": "https://www.codechef.com/problems/",
"CSA": "https://csacademy.com/contest/archive/task/",
"DMOJ": "https://dmoj.ca/problem/",
@ -16,6 +17,7 @@ const sources = {
"CSES": "https://cses.fi/problemset/task/",
"LC": "https://leetcode.com/problems/",
"ojuz": "https://oj.uz/problem/view/",
"HR": "https://www.hackerrank.com/",
};
export class Problem {

View file

@ -44,7 +44,13 @@ const ModuleOrdering: {[key: string]: ModuleOrderingItem[]} = {
"pairs-tuples",
]
},
"complete-search",
{
name: "Complete Search",
items: [
"complete-search",
"gen-perm",
]
},
"intro-graphs",
"ad-hoc"
],
@ -62,7 +68,7 @@ const ModuleOrdering: {[key: string]: ModuleOrderingItem[]} = {
items: [
"sorting-methods",
"sorting-custom",
"custom-cpp-stl",
"greedy",
]
},
{
@ -70,9 +76,9 @@ const ModuleOrdering: {[key: string]: ModuleOrderingItem[]} = {
items: [
"intro-ordered",
"harder-ordered",
"custom-cpp-stl",
]
},
"greedy",
{
name: "Stacks & Queues",
items: [

View file

@ -3,6 +3,9 @@ import { Problem } from '../../../content/models';
import Transition from '../Transition';
import renderMathInElement from 'katex/contrib/auto-render/auto-render';
import { KatexRenderer } from './KatexRenderer';
import Tooltip from '../tooltip/Tooltip';
import TextTooltip from '../tooltip/TextTooltip';
import { sourceTooltip } from './Resources';
type ProblemsListComponentProps = {
title?: string;
@ -136,12 +139,12 @@ type ProblemComponentProps = {
export function ProblemComponent(props: ProblemComponentProps) {
const difficultyClasses = {
Intro: 'bg-teal-100 text-teal-800',
Easy: 'bg-yellow-100 text-yellow-800',
Normal: 'bg-green-100 text-green-800',
'Very Easy': 'bg-gray-100 text-gray-800',
Easy: 'bg-green-100 text-green-800',
Normal: 'bg-blue-100 text-blue-800',
Hard: 'bg-purple-100 text-purple-800',
'Very Hard': 'bg-red-100 text-red-800',
Insane: 'bg-blue-100 text-blue-800',
'Very Hard': 'bg-orange-100 text-orange-800',
Insane: 'bg-red-100 text-red-800',
};
const [showTags, setShowTags] = React.useState(false);
const { problem } = props;
@ -149,7 +152,13 @@ export function ProblemComponent(props: ProblemComponentProps) {
return (
<tr>
<td className="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500 font-medium">
{problem.source}
{sourceTooltip.hasOwnProperty(problem.source) ? (
<TextTooltip content={sourceTooltip[problem.source]}>
{problem.source}
</TextTooltip>
) : (
problem.source
)}
</td>
<td className="pl-6 w-6 py-4 whitespace-no-wrap text-sm leading-5 font-medium text-gray-900">
{problem.starred && (

View file

@ -56,9 +56,15 @@ const sources = {
'cp-algo': 'https://cp-algorithms.com/',
CSA: 'https://csacademy.com/lesson/',
GFG: 'https://www.geeksforgeeks.org/',
Benq: 'https://github.com/bqi343/USACO/blob/master/Implementations/content/',
HR: 'https://www.hackerrank.com/',
};
const sourceTooltip = {
export const sourceTooltip = {
CPH: "Book - Competitive Programmer's Handbook",
PAPS: 'Book - Principles of Algorithmic Problem Solving',
IUSACO: 'Book - An Introduction to the USA Computing Olympiad',
CP1: 'Book - Competitive Programming 1',
TC: 'TopCoder',
CPC:
'Competitive Programming Course (taught at Reykjavík University, Iceland)',
@ -66,9 +72,17 @@ const sourceTooltip = {
'cp-algo': 'CP Algorithms',
CSA: 'CS Academy',
GFG: 'Geeks For Geeks',
CPH: 'Competitive Programming Handbook',
PAPS: 'Principles of Algorithmic Problem Solving',
IUSACO: 'An Introduction to the USA Computing Olympiad',
Benq: 'github.com/bqi343/USACO',
HR: 'HackerRank',
CSES: 'Code Submission Evaluation System',
HE: 'HackerEarth',
AC: 'AtCoder',
CC: 'CodeChef',
DMOJ: 'Don Mills Online Judge',
SPOJ: 'Sphere Online Judge',
YS: 'Library Checker',
LC: 'LeetCode',
POI: 'Polish Olympiad in Informatics',
};
export function ResourceComponent(props) {