fix merge conflicts
This commit is contained in:
commit
38aba9d931
29 changed files with 329 additions and 146 deletions
|
@ -7,9 +7,13 @@ problems:
|
|||
- bronze_word
|
||||
- bronze_paint
|
||||
- bronze_square
|
||||
order: 4
|
||||
order: 3
|
||||
---
|
||||
|
||||
Demonstrates how to read in input and print output for a USACO problem in multiple languages. Also lists some introductory USACO Bronze problems.
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
||||
Let's begin by solving a few fun problems! The following problems require relatively little programming experience and no algorithmic knowledge.
|
||||
|
||||
Do as many as you want, then move on! You do not have to do all of them.
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
slug: /intro/files
|
||||
title: File IO
|
||||
author: Unknown
|
||||
order: 3
|
||||
---
|
||||
|
||||
do we still need this if USACO is transitioning to standard input/output?
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
slug: /intro/containers
|
||||
slug: /bronze/containers
|
||||
title: Containers
|
||||
author: Unknown
|
||||
order: 5
|
||||
order: 2
|
||||
---
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
slug: /bronze/rectangle-geometry
|
||||
title: "Rectangle Geometry"
|
||||
author: Unknown
|
||||
order: 4
|
||||
order: 3
|
||||
---
|
||||
|
||||
See 7.1 of https://www.overleaf.com/project/5e73f65cde1d010001224d8a
|
|
@ -2,7 +2,7 @@
|
|||
slug: /bronze/simulation
|
||||
title: "Simulation"
|
||||
author: Unknown
|
||||
order: 2
|
||||
order: 4
|
||||
---
|
||||
|
||||
See 5 of https://www.overleaf.com/project/5e73f65cde1d010001224d8a
|
|
@ -2,7 +2,7 @@
|
|||
slug: /bronze/complete-search
|
||||
title: "Complete Search"
|
||||
author: Unknown
|
||||
order: 3
|
||||
order: 5
|
||||
---
|
||||
|
||||
See 6 of https://www.overleaf.com/project/5e73f65cde1d010001224d8a
|
|
@ -3,6 +3,9 @@ slug: /silver/containers
|
|||
title: "Containers"
|
||||
author: Unknown
|
||||
order: 2
|
||||
prerequisites:
|
||||
-
|
||||
- Bronze - Containers
|
||||
---
|
||||
|
||||
Containers from C++ standard template library (STL)
|
||||
|
|
|
@ -3,6 +3,9 @@ slug: /silver/sorting
|
|||
title: "Sorting"
|
||||
author: Unknown
|
||||
order: 3
|
||||
prerequisites:
|
||||
-
|
||||
- Silver - Containers
|
||||
---
|
||||
|
||||
<div class="syllabus-only">
|
||||
|
|
|
@ -3,6 +3,9 @@ slug: /silver/binary-search
|
|||
title: "Binary Search"
|
||||
author: Unknown
|
||||
order: 4
|
||||
prerequisites:
|
||||
-
|
||||
- Silver - Sorting
|
||||
---
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
|
|
@ -3,6 +3,9 @@ slug: /silver/two-pointers
|
|||
title: "Two Pointers"
|
||||
author: Unknown
|
||||
order: 5
|
||||
prerequisites:
|
||||
-
|
||||
- Silver - Sorting
|
||||
---
|
||||
|
||||
- CPH 8.1
|
||||
|
|
|
@ -4,24 +4,22 @@ title: "Dynamic Programming"
|
|||
author: Michael Cao
|
||||
order: 1
|
||||
prerequisites:
|
||||
-
|
||||
- Prefix Sums
|
||||
-
|
||||
- Recursion
|
||||
-
|
||||
- Bit Operations (for Bitmask DP)
|
||||
-
|
||||
- Silver - Prefix Sums
|
||||
-
|
||||
- DFS and Trees (for Tree DP)
|
||||
- Silver - Depth First Search (for Tree DP)
|
||||
|
||||
<div class="syllabus-only">
|
||||
An introduction into Dynamic Programming concepts needed (and not-so-needed but still useful) for USACO gold.
|
||||
</div>
|
||||
An introduction to Dynamic Programming concepts needed (and not-so-needed but still useful) for USACO Gold.
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
||||
## Introduction to DP
|
||||
|
||||
Dynamic Programming is a very important concept which emerges in the USACO gold division and extends to the IOI. Typically, one or two problems from every contest in the gold division uses some sort of Dynamic programming. The following tutorials serve as an introduction into the mindset of Dynamic programming.
|
||||
Dynamic Programming is a very important concept which emerges in the USACO gold division and extends to the IOI. Typically, one or two problems from every contest in the gold division uses some sort of Dynamic programming. The following tutorials serve as an introduction into the mindset of Dynamic programming.
|
||||
|
||||
- CPH 7 (Great introduction that covers most classical problems)
|
||||
- [Topcoder DP (Great for all skill levels)](https://www.topcoder.com/community/competitive-programming/tutorials/dynamic-programming-from-novice-to-advanced/)
|
||||
|
|
33
content/3_Gold/2_Gold_BFS.md
Normal file
33
content/3_Gold/2_Gold_BFS.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
slug: /gold/bfs
|
||||
title: "Breadth First Search"
|
||||
author: Benjamin Qi
|
||||
order: 2
|
||||
prerequisites:
|
||||
-
|
||||
- Silver - Depth First Search
|
||||
---
|
||||
|
||||
Compute shortest paths where all edge weights are 1.
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
||||
## Breadth First Search
|
||||
|
||||
- [CSES Message Route](https://cses.fi/problemset/task/1667)
|
||||
|
||||
### Tutorial
|
||||
|
||||
- CSES 12.2
|
||||
- [CSAcademy BFS](https://csacademy.com/lesson/breadth_first_search)
|
||||
- [cp-algo BFS](https://cp-algorithms.com/graph/breadth-first-search.html)
|
||||
- [cp-algo 0/1 BFS](https://cp-algorithms.com/graph/01_bfs.html)
|
||||
- [KhanAcademy BFS](https://www.khanacademy.org/computing/computer-science/algorithms/breadth-first-search/a/breadth-first-search-and-its-uses)
|
||||
|
||||
### Problems
|
||||
|
||||
- [CSAcademy BFS-DFS](https://csacademy.com/contest/round-41/task/bfs-dfs/) [](50)
|
||||
- [Cow Navigation](http://www.usaco.org/index.php?page=viewproblem2&cpid=695)
|
||||
- [Dream](http://www.usaco.org/index.php?page=viewproblem2&cpid=575)
|
||||
- [Lasers](http://www.usaco.org/index.php?page=viewproblem2&cpid=671)
|
||||
- [Monsters](https://cses.fi/problemset/task/1194)
|
|
@ -1,16 +1,15 @@
|
|||
---
|
||||
slug: /gold/topological-sort
|
||||
slug: /gold/toposort
|
||||
title: "Topological Sort"
|
||||
author: Benjamin Qi
|
||||
order: 4
|
||||
order: 3
|
||||
prerequisites:
|
||||
-
|
||||
- Gold - Breadth First Search
|
||||
---
|
||||
|
||||
Assumes familiarity with "Silver - Depth First Search."
|
||||
|
||||
A [topological sort](https://en.wikipedia.org/wiki/Topological_sorting) of a directed 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.
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
||||
## Example Problems
|
||||
|
||||
- [CSES Course Schedule](https://cses.fi/problemset/task/1679)
|
||||
|
@ -19,9 +18,11 @@ A [topological sort](https://en.wikipedia.org/wiki/Topological_sorting) of a dir
|
|||
|
||||
## Tutorial
|
||||
|
||||
(BFS Implementation?)
|
||||
|
||||
- CPH 16.1, 16.2
|
||||
- [cp-algorithms](https://cp-algorithms.com/graph/topological-sort.html)
|
||||
-
|
||||
- [CSAcademy](https://csacademy.com/lesson/topological_sorting)
|
||||
|
||||
## Problems
|
||||
|
|
@ -2,39 +2,18 @@
|
|||
slug: /gold/sp
|
||||
title: "Shortest Paths"
|
||||
author: Benjamin Qi
|
||||
order: 2
|
||||
order: 4
|
||||
prerequisites:
|
||||
-
|
||||
- Gold - Breadth First Search
|
||||
---
|
||||
|
||||
Assumes familiarity with "Silver - Depth First Search."
|
||||
|
||||
- Breadth First Search
|
||||
- Shortest Path With and Without Negative Edge Weights
|
||||
- Shortest Path Without Negative Edge Weights
|
||||
- Shortest Path With Negative Edge Weights
|
||||
- All Pairs Shortest Path
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
||||
## Breadth First Search
|
||||
|
||||
Find the shortest path where all edge weights are 1.
|
||||
|
||||
- [CSES Message Route](https://cses.fi/problemset/task/1667)
|
||||
|
||||
### Tutorial
|
||||
|
||||
- CSES 12.2
|
||||
- [CSAcademy BFS](https://csacademy.com/lesson/breadth_first_search)
|
||||
- [cp-algo BFS](https://cp-algorithms.com/graph/breadth-first-search.html)
|
||||
- [cp-algo 0/1 BFS](https://cp-algorithms.com/graph/01_bfs.html)
|
||||
- [KhanAcademy BFS](https://www.khanacademy.org/computing/computer-science/algorithms/breadth-first-search/a/breadth-first-search-and-its-uses)
|
||||
|
||||
### Problems
|
||||
|
||||
- [CSAcademy BFS-DFS](https://csacademy.com/contest/round-41/task/bfs-dfs/) [](50)
|
||||
- [Cow Navigation](http://www.usaco.org/index.php?page=viewproblem2&cpid=695)
|
||||
- [Dream](http://www.usaco.org/index.php?page=viewproblem2&cpid=575)
|
||||
- [Lasers](http://www.usaco.org/index.php?page=viewproblem2&cpid=671)
|
||||
- [Monsters](https://cses.fi/problemset/task/1194)
|
||||
|
||||
## Non-Negative Edge Weights
|
||||
|
||||
Use *Dijkstra's Algorithm*.
|
|
@ -1,13 +1,14 @@
|
|||
---
|
||||
slug: /gold/mst
|
||||
title: "Minimum Spanning Tree"
|
||||
title: "Minimum Spanning Trees"
|
||||
author: Benjamin Qi
|
||||
order: 3
|
||||
order: 5
|
||||
prerequisites:
|
||||
-
|
||||
- Gold - Shortest Paths
|
||||
---
|
||||
|
||||
Assumes familiarity with "Gold - Shortest Paths."
|
||||
|
||||
Disjoint Set Union and Minimum Spanning Tree
|
||||
Disjoint Set Union and Minimum Spanning Trees
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
||||
|
@ -50,4 +51,8 @@ Disjoint Set Union and Minimum Spanning Tree
|
|||
## Other Problems
|
||||
|
||||
- [Birthday Gifts](https://www.hackerearth.com/practice/math/combinatorics/inclusion-exclusion/practice-problems/algorithm/mancunian-and-birthday-gifts-d44faa15/) [](73)
|
||||
- [Spanning Tree Fraction](https://www.hackerrank.com/contests/w31/challenges/spanning-tree-fraction) [](78)
|
||||
- [Spanning Tree Fraction](https://www.hackerrank.com/contests/w31/challenges/spanning-tree-fraction) [](78)
|
||||
|
||||
## Boruvka?
|
||||
|
||||
(add)
|
|
@ -2,11 +2,12 @@
|
|||
slug: /gold/bit
|
||||
title: "Binary Indexed Trees"
|
||||
author: Benjamin Qi
|
||||
order: 5
|
||||
order: 6
|
||||
prerequisites:
|
||||
-
|
||||
- Silver - Prefix Sums
|
||||
---
|
||||
|
||||
Assumes familiarity with "Silver - Prefix Sums."
|
||||
|
||||
A **Binary Indexed 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).
|
|
@ -2,7 +2,7 @@
|
|||
slug: /gold/introductory-number-theory
|
||||
title: "Introductory Number Theory"
|
||||
author: Unknown
|
||||
order: 6
|
||||
order: 7
|
||||
---
|
||||
|
||||
<div class="syllabus-only">
|
|
@ -3,6 +3,9 @@ slug: /plat/trees
|
|||
title: "Trees"
|
||||
author: Benjamin Qi
|
||||
order: 1
|
||||
prerequisites:
|
||||
-
|
||||
- Silver - Depth First Search
|
||||
---
|
||||
|
||||
Lowest Common Ancestor and other tree topics.
|
||||
|
|
|
@ -3,10 +3,11 @@ slug: /plat/1DRQ
|
|||
title: "1D Range Queries"
|
||||
author: Benjamin Qi
|
||||
order: 2
|
||||
prerequisites:
|
||||
-
|
||||
- Gold - Binary Indexed Trees
|
||||
---
|
||||
|
||||
Assumes familiarity with "Gold - Binary Indexed Trees."
|
||||
|
||||
General range queries for associative operations, including segment tree.
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
@ -70,8 +71,4 @@ Binary Indexed Trees can support range increments in addition to range sum queri
|
|||
|
||||
Example problem:
|
||||
|
||||
- [DMOJ Range Update Range Query](https://dmoj.ca/problem/acc3p4)
|
||||
|
||||
You can extend this to higher dimensions as well (USACO Camp - "Cows Play Global Thermonuclear War").
|
||||
|
||||
- [Paper](https://arxiv.org/pdf/1311.6093.pdf)
|
||||
- [DMOJ Range Update Range Query](https://dmoj.ca/problem/acc3p4)
|
|
@ -3,11 +3,12 @@ slug: /plat/2DRQ
|
|||
title: "2D Range Queries"
|
||||
author: Benjamin Qi
|
||||
order: 3
|
||||
prerequisites:
|
||||
-
|
||||
- Platinum - 1D Range Queries
|
||||
---
|
||||
|
||||
Assumes familiarity with "Platinum - 1D Range Queries."
|
||||
|
||||
Extending 1D Range Queries to 2D (and beyond).
|
||||
Extending Range Queries to 2D (and beyond).
|
||||
|
||||
<!-- END DESCRIPTION -->
|
||||
|
||||
|
@ -25,6 +26,10 @@ See [my implementations](https://github.com/bqi343/USACO/tree/master/Implementat
|
|||
- [GFG 2D BIT](https://www.geeksforgeeks.org/two-dimensional-binary-indexed-tree-or-fenwick-tree/)
|
||||
- [TopCoder BIT](https://www.topcoder.com/community/competitive-programming/tutorials/binary-indexed-trees/)
|
||||
|
||||
You can extend the 1D BIT solution for range update + range query to higher dimensions as well (USACO Camp - "Cows Play Global Thermonuclear War").
|
||||
|
||||
- [Paper](https://arxiv.org/pdf/1311.6093.pdf)
|
||||
|
||||
### Problems
|
||||
|
||||
- [CSES Forest Queries II](https://cses.fi/problemset/task/1739)
|
||||
|
@ -36,6 +41,8 @@ See [my implementations](https://github.com/bqi343/USACO/tree/master/Implementat
|
|||
|
||||
## 2D Segment Tree
|
||||
|
||||
Note: no lazy propagation in 2D.
|
||||
|
||||
- Short Description
|
||||
- CSES 28.2, 28.4
|
||||
- Segment Tree (or BIT) nested inside segment tree
|
||||
|
|
|
@ -3,6 +3,9 @@ slug: /plat/graphs
|
|||
title: "Graphs"
|
||||
author: Benjamin Qi
|
||||
order: 5
|
||||
prerequisites:
|
||||
-
|
||||
- Gold - Topological Sort
|
||||
---
|
||||
|
||||
- Eulerian Tours
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
---
|
||||
slug: /plat/hashing
|
||||
title: "Platinum - Strings"
|
||||
title: "Strings"
|
||||
author: Benjamin Qi
|
||||
order: 6
|
||||
prerequisites:
|
||||
-
|
||||
- Silver - Depth First Search
|
||||
---
|
||||
|
||||
- Tries
|
||||
|
|
|
@ -3,6 +3,11 @@ slug: /plat/fracture
|
|||
title: "Fracturing Search"
|
||||
author: Benjamin Qi
|
||||
order: 8
|
||||
prerequisites:
|
||||
-
|
||||
- Gold - Minimum Spanning Tree
|
||||
-
|
||||
- some familiarity with "Robotic Cow Herd" analysis
|
||||
---
|
||||
|
||||
A simple solution to [Robotic Cow Herd](http://www.usaco.org/index.php?page=viewproblem2&cpid=674) that generalizes.
|
||||
|
@ -13,32 +18,60 @@ A simple solution to [Robotic Cow Herd](http://www.usaco.org/index.php?page=view
|
|||
|
||||
### Problem
|
||||
|
||||
Suppose that you have a rooted tree where each vertex $i$ has a value $v_i$ and parent $p_i$ (if $i$ is not the root). Given that $v_{p_i} \le v_i$ and each vertex has at most $D$ children, find the $K$ smallest values in the tree.
|
||||
Suppose that you have a rooted tree where each vertex $i$ has a value $v_i$. Also, if $i$ is not the root then $i$ has a parent $p_i$ satisfying $v_{p_i} \le v_i$. Given that each vertex has at most $D$ children, find the $K$ smallest values in the tree.
|
||||
|
||||
### Solution
|
||||
### Approaches
|
||||
|
||||
Use a priority queue. At each step, extract the vertex with smallest value from the priority queue and insert all of its children into the queue. Since we insert $O(KD)$ vertices in the priority queue, this solution takes $O(KD\log (KD))$ time.
|
||||
**Approach 1:** Use a priority queue initially containing only the root. At each step, extract the vertex with smallest value from the priority queue and insert all of its children into the queue. Since we insert $O(KD)$ vertices in the priority queue, this runs in $O(KD\log (KD))$ time. You can think of this as Dijkstra on a tree.
|
||||
|
||||
The above approach can be generalized. Suppose that you want to find the $K$ objects with the smallest values in some (potentially very large) search space. Start with the "root," namely the object with the smallest value. Every other object in the space should have a single "parent" whose value is not greater. Furthermore, the number of children of each object should be reasonably bounded (i.e. $D$ is small).
|
||||
**Approach 2:** Suppose that we know that the $K$-th smallest value is an integer in the range $[0,A]$. Then for any $x\in [0,A]$ we can check whether there are less than $K$ values in the tree less than or equal to $x$ in $O(KD)$ time with a simple DFS that breaks once you find $K$ values. This approach runs in $O(KD\log A)$ time.
|
||||
|
||||
We'll focus on the first approach.
|
||||
|
||||
### Generalizing
|
||||
|
||||
Suppose that you want to find the $K$ objects with the smallest values in some (potentially very large) search space.
|
||||
|
||||
- First, we need to impose a tree structure satisfying the properties mentioned above. Say that $b$ lies in the subtree of $a$ if $a$ lies above (or is equal to) $b$ in the tree.
|
||||
- Let the "root" be the object of smallest value. Every object must lie in the subtree of the root.
|
||||
- The children of the root should partition the entire search space (aside from the root) into a bounded number of disjoint subspaces.
|
||||
- Of course, each child should also have the smallest value in its subtree.
|
||||
|
||||
Essentially, we start with the entire search space and then we *fracture* it into *subspaces* based on the children of the root. Then we can finish with either of the two approaches.
|
||||
|
||||
## Finding K-th Smallest Spanning Tree (USACO Camp 2018)
|
||||
|
||||
Let's look at an example.
|
||||
|
||||
### Problem
|
||||
|
||||
Given a graph with $N\le 50$ vertices and at most $\binom{N}{2}$ edges, find the $K$-th ($K\le 10^4$) smallest spanning tree.
|
||||
|
||||
(Note: not solved in contest.)
|
||||
|
||||
### Solution
|
||||
|
||||
For this problem, the objects are spanning trees and the "root" is the minimum spanning tree. If we can somehow ensure that each object has at most $N$ "children" then we only need to consider $O(NK)$ spanning trees in order to find the $K$-th smallest. Essentially, we start with a search space consisting of all possible spanning trees and then we "fracture" it based on the children of the root.
|
||||
|
||||
[Video (by tehqin)](https://www.youtube.com/watch?v=EG_HfFMM0lE)
|
||||
|
||||
For this problem, the objects are spanning trees. The root is the minimum spanning tree (which can be calculated with Kruskal's algorithm), and contains all objects in its subtree.
|
||||
|
||||
The idea is to designate a small number of children of the root, each of which should be formed by modifying the root slightly. If we can somehow ensure that each object has at most $N$ "children" then we only need to consider $O(NK)$ spanning trees in order to find the $K$-th smallest.
|
||||
|
||||
The first step is to consider the easier problem of finding the second MST. To do this, we can choose to exclude one edge of the MST and then find the smallest possible replacement for it. Let the edges in the MST be labeled $1\ldots N-1$. Then one idea is to let the $i$-th child subspace of the root to consist of all spanning trees not including edge $i$ of the minimum spanning tree for each $i\in [1,N-1]$.
|
||||
|
||||
Unfortunately, this doesn't work because the child subspaces overlap. We can instead let the $i$-th child subspace contain all spanning trees that
|
||||
|
||||
- include the first $i-1$ edges of the MST
|
||||
- do not include the $i$-th edge of the MST
|
||||
|
||||
for each $i\in [1,N-1]$. Every spanning tree other than the root is contained within exactly one of these child subspaces, which is what we want. After sorting the edges in increasing order of weight once, we can compute the MST within each child subspace in $O(M\alpha (N))$ time with DSU.
|
||||
|
||||
Overall, the runtime is $O(NMK\alpha(N))$ for storing the information about each spanning tree and $O(NK\log (NK))$ for maintaing the priority queue of objects so that we can extract the minimum. Note that with the second approach mentioned in the first section the running time would instead be $O(NMK\alpha(N)\log ans)$, which may be too slow.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>My Solution</summary>
|
||||
|
||||
This is equivalent to the solution given in the video. The runtime is $O(NMK\alpha(N))$ for storing the information about each spanning tree and $O(NK\log (NK))$ for the priority queue.
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
@ -61,9 +94,9 @@ int N,M,K;
|
|||
vector<array<int,3>> ed;
|
||||
|
||||
struct Partition {
|
||||
B ban; vi span; int wei = 0, fix = 0; // "fix" smallest edges in spanning tree
|
||||
B ban; vi span; int wei = 0, fix = 0; // "fix" smallest edges must be contained in spanning tree
|
||||
Partition(B _ban, int _fix) : ban(_ban), fix(_fix) {
|
||||
DSU D; D.init(N);
|
||||
DSU D; D.init(N); // now find MST within subspace
|
||||
for (int i = 0; i < M; ++i) if (!ban[i] && D.unite(ed[i][1],ed[i][2]))
|
||||
span.push_back(i), wei += ed[i][0]; // run Kruskal's ignoring banned edges
|
||||
}
|
||||
|
@ -99,27 +132,118 @@ int main() {
|
|||
|
||||
## [USACO Robotic Cow Herd](http://www.usaco.org/index.php?page=viewproblem2&cpid=674)
|
||||
|
||||
The first solution in the analysis contains an extra log factor, while the second is overly complicated. Thankfully, fracturing search allows us to construct the $K$ smallest robots in $O(K\log K)$ time. As before, we want each robot to have a bounded number ($D$) of "child" robots, where each robot aside from the root has exactly one parent robot and the cost of the parent is always at most the cost of the child. In fact, we can let $D=3$.
|
||||
As with the analysis, for each location you should
|
||||
|
||||
As with the analysis, first sort the controllers of each type by cost, and then add the controller of minimum cost for each position to the answer (and subtract that cost from each controller at that position). Then sort the positions by the cost of the second-minimum controller at that position.
|
||||
- sort the controllers of that location by cost
|
||||
- add the controller of minimum cost for each location to the cost of the cheapest robot
|
||||
- subtract that minimum cost from every controller at that location (so now the minimum cost controller for each location is just zero)
|
||||
|
||||
First start with the robot of minimum cost. Then the robot with second-minimum cost can be formed by just choosing the second-minimum controller for the first position. After this, we have a few options:
|
||||
Importantly, we should then sort the locations by their respective second-minimum controller costs.
|
||||
|
||||
* We can choose the third-minimum controller for the first position.
|
||||
* We can discard the second-minimum controller for the first position and select the second-minimum controller for the second position (and never again change the controller selected for the first position).
|
||||
* We can keep the second-minimum controller for the first position and select the second-minimum controller for the second position (and never again change the controller selected for the first position).
|
||||
## Approach 1
|
||||
|
||||
Note that none of these options result in a robot of lower cost since we assumed that we sorted the positions by second-minimum controller. In general, suppose that we have a robot and are currently selecting the $j$-th cheapest controller for the $i$-th position. Then the transitions are as follows:
|
||||
Binary search on the cost $c$ of the $K$-th robot. If we can compute the costs of all robots with cost at most $c$ or say that there are more than $K$ in $O(K)$ time, then we can solve this problem in $O(N\log N+K\log \max(c))$ time (similar to "Approach 2" above). This is the approach that the first analysis solution takes, although it includes an extra $\log N$ factor due to `upper_bound`. I have removed this in my solution below.
|
||||
|
||||
* Select the $j+1$-th cheapest controller for the $i$-th position instead.
|
||||
* If $j=2$, select the $1$-st cheapest controller for the $i$-th position instead and also select the $2$-nd cheapest controller for the $i+1$-st.
|
||||
* Keep the $j$-th cheapest controller for the $i$-th position and also select the $2$-nd cheapest controller for the $i+1$-st.
|
||||
<details>
|
||||
|
||||
<summary>My Solution 1</summary>
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
typedef long long ll;
|
||||
typedef vector<int> vi;
|
||||
typedef pair<ll,ll> pl;
|
||||
|
||||
#define f first
|
||||
#define s second
|
||||
|
||||
int N,K;
|
||||
ll tot; // sum of cheapest
|
||||
vector<vi> v;
|
||||
|
||||
ll mx; ll res; int num;
|
||||
|
||||
void dfs(int pos, ll cur, int id) {
|
||||
if (cur > mx || num == K) return;
|
||||
res += cur; num ++;
|
||||
if (id+1 < v[pos].size()) dfs(pos,cur+v[pos][id+1]-v[pos][id],id+1);
|
||||
for (int i = pos+1; i < v.size(); ++i) {
|
||||
ll CUR = cur+v[i][1];
|
||||
if (num == K || CUR > mx) break;
|
||||
dfs(i,CUR,1);
|
||||
}
|
||||
}
|
||||
|
||||
void get() {
|
||||
res = num = 0;
|
||||
dfs(0,tot,0);
|
||||
}
|
||||
|
||||
int main() {
|
||||
ios_base::sync_with_stdio(0); cin.tie(0);
|
||||
freopen("roboherd.in","r",stdin);
|
||||
freopen("roboherd.out","w",stdout);
|
||||
cin >> N >> K;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
int m; cin >> m;
|
||||
vi p(m); for (int& x: p) cin >> x;
|
||||
sort(begin(p),end(p));
|
||||
tot += p[0]; for (int j = m-1; j >= 0; --j) p[j] -= p[0];
|
||||
if (p.size() > 1) v.push_back(p);
|
||||
}
|
||||
sort(begin(v),end(v)); // sort by second-cheapest
|
||||
ll lo = 0, hi = 1e13;
|
||||
while (lo < hi) {
|
||||
mx = (lo+hi+1)/2; get();
|
||||
if (num < K) lo = mx;
|
||||
else hi = mx-1;
|
||||
}
|
||||
mx = lo; get();
|
||||
cout << res+(K-num)*(mx+1) << "\n";
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Approach 2
|
||||
|
||||
There's also an $O(N\log N+K\log K)$ time solution with a priority queue that constructs the robots in increasing order of cost. As before, we want each robot to have a bounded number of "child" robots. However, if you look at my DFS function above, it seems that every robot can have up to $N$ children! Nevertheless, the DFS takes $O(K)$ rather than $O(KN)$ time due to the break statement, which works since we sorted by second-cheapest robot.
|
||||
|
||||
In fact, we can modify the DFS function so that every robot has at most three rather than $N$ children.
|
||||
|
||||
```cpp
|
||||
void dfs(int pos, ll cur, int id) {
|
||||
if (cur > mx || num == K) return;
|
||||
res += cur; num ++;
|
||||
if (id+1 < v[pos].size()) dfs(pos,cur+v[pos][id+1]-v[pos][id],id+1);
|
||||
if (pos+1 < v.size()) {
|
||||
if (id == 1) dfs(pos+1,cur-v[pos][1]+v[pos+1][1],1);
|
||||
if (id) dfs(pos+1,cur+v[pos+1][1],1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now I'll describe what how the priority queue solution works:
|
||||
|
||||
First start with the robot of minimum cost. The robot with second-minimum cost can be formed by just choosing the second-minimum controller for the first location. After this, we have a few options:
|
||||
|
||||
- We can choose the third-minimum controller for the first location.
|
||||
- We can discard the second-minimum controller for the first location and select the second-minimum controller for the second location (and never again change the controller selected for the first location).
|
||||
- We can keep the second-minimum controller for the first location and select the second-minimum controller for the second location (and never again change the controller selected for the first location).
|
||||
|
||||
None of these options can result in a robot of lower cost. In general, suppose that we have a robot and are currently selecting the $j$-th cheapest controller for the $i$-th location. Then the transitions are as follows:
|
||||
|
||||
- Select the $j+1$-th cheapest controller for the $i$-th location instead.
|
||||
- If $j=2$, select the $1$-st cheapest controller for the $i$-th location instead and also select the $2$-nd cheapest controller for the $i+1$-st.
|
||||
- Keep the $j$-th cheapest controller for the $i$-th location and also select the $2$-nd cheapest controller for the $i+1$-st.
|
||||
|
||||
Since there exists exactly one way to get from the cheapest robot to every possible robot, we can just use a priority queue.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>My Solution</summary>
|
||||
<summary>My Solution 2</summary>
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
|
@ -155,13 +279,13 @@ int main() {
|
|||
ll ans = 0;
|
||||
for (int i = 0; i < K; ++i) {
|
||||
auto a = pq.top(); pq.pop();
|
||||
ans += tot+a.f; int ind = a.s.f, pos = a.s.s;
|
||||
if (ind+1 < v.size()) {
|
||||
if (pos == 1) pq.push({a.f-v[ind][1]+v[ind+1][1],{ind+1,1}});
|
||||
if (pos) pq.push({a.f+v[ind+1][1],{ind+1,1}});
|
||||
ans += tot+a.f; int pos = a.s.f, id = a.s.s;
|
||||
if (id+1 < v[pos].size())
|
||||
pq.push({a.f+v[pos][id+1]-v[pos][id],{pos,id+1}});
|
||||
if (pos+1 < v.size()) {
|
||||
if (id == 1) pq.push({a.f-v[pos][1]+v[pos+1][1],{pos+1,1}});
|
||||
if (id) pq.push({a.f+v[pos+1][1],{pos+1,1}});
|
||||
}
|
||||
if (pos+1 < v[ind].size())
|
||||
pq.push({a.f+v[ind][pos+1]-v[ind][pos],{ind,pos+1}});
|
||||
}
|
||||
cout << ans << "\n";
|
||||
}
|
||||
|
@ -171,6 +295,6 @@ int main() {
|
|||
|
||||
## Other Problems
|
||||
|
||||
* [Baltic OI 2019 - Olympiads](https://boi2019.eio.ee/tasks/)
|
||||
* [CCO 20 Shopping Plans](https://dmoj.ca/problem/cco20p6)
|
||||
* Generalization of Robotic Cow Herd
|
||||
- [Baltic OI 2019 - Olympiads](https://cses.fi/248/submit/D)
|
||||
- [CCO 20 Shopping Plans](https://dmoj.ca/problem/cco20p6)
|
||||
- Generalization of Robotic Cow Herd
|
|
@ -3,6 +3,9 @@ slug: /plat/slope
|
|||
title: "Slope Trick"
|
||||
author: Benjamin Qi
|
||||
order: 9
|
||||
prerequisites:
|
||||
-
|
||||
- some familiarity with at least one of the two tutorials mentioned in this module
|
||||
---
|
||||
|
||||
**Slope trick** refers to manipulating piecewise linear convex functions. Includes a simple solution to [Landscaping](http://www.usaco.org/index.php?page=viewproblem2&cpid=650).
|
||||
|
@ -11,22 +14,18 @@ order: 9
|
|||
|
||||
## Tutorials
|
||||
|
||||
Links:
|
||||
|
||||
* [zscoder](https://codeforces.com/blog/entry/47821)
|
||||
* [Kuroni](https://codeforces.com/blog/entry/77298)
|
||||
- [zscoder](https://codeforces.com/blog/entry/47821)
|
||||
- [Kuroni](https://codeforces.com/blog/entry/77298)
|
||||
|
||||
From the latter link (modified):
|
||||
|
||||
> Slope trick is a way to represent a function that satisfies the following conditions:
|
||||
>
|
||||
> * It can be divided into multiple sections, where each section is a linear function (usually) with an integer slope.
|
||||
> * It is a convex/concave function. In other words, the slope of each section is non-decreasing or non-increasing when scanning the function from left to right.
|
||||
> - It can be divided into multiple sections, where each section is a linear function (usually) with an integer slope.
|
||||
> - It is a convex/concave function. In other words, the slope of each section is non-decreasing or non-increasing when scanning the function from left to right.
|
||||
|
||||
It's generally applicable as a DP optimization. Usually you can come up with a slower DP (ex. $O(N^2)$) first and then optimize it to $O(N\log N)$ with slope trick.
|
||||
|
||||
This document assumes some familiarity with at least one of the links above (and provides a few more examples).
|
||||
|
||||
## A Simple Example
|
||||
|
||||
[CF Buy Low Sell High](https://codeforces.com/contest/866/problem/D)
|
||||
|
|
|
@ -17,7 +17,8 @@ const renderProblem = (problem, idx) => {
|
|||
return (
|
||||
<li className="flex items-center" key={problem}>
|
||||
{idx>0?<IncompleteCheck/>:<CompletedCheck/>}
|
||||
<a className="text-blue-600" href="#">{problem}</a>
|
||||
{/* todo make url legit */}
|
||||
<a className="text-blue-600" href="https://google.com/">{problem}</a>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
@ -37,7 +38,7 @@ const SyllabusModule = ({ title, children, author, problems, prerequisites, url
|
|||
const isComplete = title === "Prerequisites" || title === "Getting Started";
|
||||
|
||||
return (
|
||||
<div className="bg-white overflow-hidden shadow rounded-lg mb-8">
|
||||
<div className="bg-white overflow-hidden shadow rounded-lg mb-8" id={url}>
|
||||
<div className="border-b border-gray-200 px-4 py-4 sm:px-6 flex items-center">
|
||||
<h2 className="font-bold text-xl mr-2">
|
||||
{title}
|
||||
|
@ -48,14 +49,16 @@ const SyllabusModule = ({ title, children, author, problems, prerequisites, url
|
|||
<path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>}
|
||||
</div>
|
||||
{prerequisites&&
|
||||
<div className="p-4 sm:p-6 border-b border-gray-200">
|
||||
Prerequisites: <ul className="ml-8 list-disc">{prerequisites.map(renderPrerequisite)}</ul>
|
||||
</div>}
|
||||
<div className="px-4 py-4 sm:p-6">
|
||||
{children}
|
||||
|
||||
{prerequisites&&(<>Prerequisites:<ul className="ml-8 list-disc">{prerequisites.map(renderPrerequisite)}</ul></>)}
|
||||
|
||||
{problems&&(<>Problems:<ul className="ml-3 space-y-1 py-2">{problems.map(renderProblem)}</ul></>)}
|
||||
|
||||
{author&&<p className="mt-2 text-gray-500">Author: {author}</p>}
|
||||
{author&&<p className="mt-2">Author: {author}</p>}
|
||||
</div>
|
||||
<Link to={url || "/"}
|
||||
className="block border-t border-gray-200 px-4 py-4 sm:px-6 text-blue-600 font-bold uppercase text-sm hover:bg-gray-50 transition duration-150">
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from "react"
|
|||
import Layout from "../components/layout"
|
||||
import SEO from "../components/seo"
|
||||
import SyllabusModule from "../components/SyllabusModule";
|
||||
import { graphql } from "gatsby";
|
||||
import { graphql, Link, navigate } from "gatsby";
|
||||
import Markdown from "../components/Markdown";
|
||||
|
||||
const renderModule = ({ node }) => {
|
||||
|
@ -24,16 +24,22 @@ const renderModule = ({ node }) => {
|
|||
);
|
||||
};
|
||||
|
||||
const IndexPage = ({ data }) => {
|
||||
const IndexPage = ({ data, ...props }) => {
|
||||
const introModules = data.introModules.edges;
|
||||
const bronzeModules = data.bronzeModules.edges;
|
||||
const silverModules = data.silverModules.edges;
|
||||
const goldModules = data.goldModules.edges;
|
||||
const platModules = data.platModules.edges;
|
||||
const modules = [introModules, bronzeModules, silverModules, goldModules, platModules];
|
||||
|
||||
const [selectedDivision, setSelectedDivision] = React.useState(0);
|
||||
let defaultDivision = 0;
|
||||
if (props.location?.search) {
|
||||
defaultDivision = props.location.search[props.location.search.length-1]-'0';
|
||||
}
|
||||
const [selectedDivision, setSelectedDivision] = React.useState(defaultDivision);
|
||||
const colors = ["blue", "orange", "teal", "yellow", "purple"];
|
||||
const color = colors[selectedDivision];
|
||||
const module = modules[selectedDivision];
|
||||
|
||||
// for purgecss, we have to list all the classes that are dynamically generated...
|
||||
/*
|
||||
|
@ -51,14 +57,19 @@ const IndexPage = ({ data }) => {
|
|||
// alternatively we can just not dynamically generate classes, but that seems more tedious.
|
||||
|
||||
const selectedTabClasses = `flex-1 py-4 px-1 text-center border-b-2 border-${color}-500 font-bold text-lg leading-5 text-${color}-600 focus:outline-none focus:text-${color}-800 focus:border-${color}-700`,
|
||||
unselectedTabClasses = `flex-1 py-4 px-1 text-center border-b-2 border-transparent font-bold text-lg leading-5 text-gray-500 hover:text-gray-700 hover:border-${color}-300 focus:outline-none focus:text-gray-700 focus:border-${color}-300`;
|
||||
unselectedTabClasses = `flex-1 py-4 px-1 text-center border-b-2 border-transparent font-bold text-lg leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300`;
|
||||
|
||||
const handleDivisionChange = d => {
|
||||
setSelectedDivision(d);
|
||||
navigate("?division="+d, { replace: true });
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<SEO title="Home" />
|
||||
|
||||
{/* Begin Hero Section */}
|
||||
<div className={`relative bg-${color}-600 overflow-hidden transition duration-150`}>
|
||||
<div className={`relative bg-${color}-600 overflow-hidden transition duration-300 pb-28`}>
|
||||
<div className="hidden sm:block sm:absolute sm:inset-y-0 sm:h-full sm:w-full">
|
||||
<div className="relative h-full max-w-screen-xl mx-auto">
|
||||
<svg className="absolute right-full transform translate-y-1/4 translate-x-1/4 lg:translate-x-1/2"
|
||||
|
@ -110,13 +121,12 @@ const IndexPage = ({ data }) => {
|
|||
{/* End Hero Section */}
|
||||
|
||||
<div className="bg-gray-50 pb-8" id="content">
|
||||
<div className="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 py-4 lg:py-8">
|
||||
|
||||
<div className="mb-8 bg-white shadow-md rounded-lg">
|
||||
<div className="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 pb-4">
|
||||
<div className="mb-8 bg-white shadow-md rounded-lg relative" style={{ marginTop: "-8rem" }}>
|
||||
<div className="sm:hidden">
|
||||
<select aria-label="Selected tab"
|
||||
className="form-select block w-full"
|
||||
onChange={e => setSelectedDivision(e.target.value - '0')}
|
||||
onChange={e => handleDivisionChange(e.target.value - '0')}
|
||||
value={selectedDivision}
|
||||
>
|
||||
<option value={0}>Intro</option>
|
||||
|
@ -126,43 +136,47 @@ const IndexPage = ({ data }) => {
|
|||
<option value={4}>Platinum</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="hidden sm:block">
|
||||
<nav className="flex">
|
||||
<a href="#"
|
||||
onClick={e => {e.preventDefault(); setSelectedDivision(0)}}
|
||||
<div className="hidden sm:block border-b border-gray-200">
|
||||
<nav className="flex -mb-px">
|
||||
<a href="?division=0"
|
||||
onClick={e => {e.preventDefault(); handleDivisionChange(0)}}
|
||||
className={selectedDivision === 0 ? selectedTabClasses : unselectedTabClasses}>
|
||||
Intro
|
||||
</a>
|
||||
<a href="#"
|
||||
onClick={e => {e.preventDefault(); setSelectedDivision(1)}}
|
||||
<a href="?division=1"
|
||||
onClick={e => {e.preventDefault(); handleDivisionChange(1)}}
|
||||
className={selectedDivision === 1 ? selectedTabClasses : unselectedTabClasses}>
|
||||
Bronze
|
||||
</a>
|
||||
<a href="#"
|
||||
onClick={e => {e.preventDefault(); setSelectedDivision(2)}}
|
||||
<a href="?division=2"
|
||||
onClick={e => {e.preventDefault(); handleDivisionChange(2)}}
|
||||
className={selectedDivision === 2 ? selectedTabClasses : unselectedTabClasses}
|
||||
aria-current="page">
|
||||
Silver
|
||||
</a>
|
||||
<a href="#"
|
||||
onClick={e => {e.preventDefault(); setSelectedDivision(3)}}
|
||||
<a href="?division=3"
|
||||
onClick={e => {e.preventDefault(); handleDivisionChange(3)}}
|
||||
className={selectedDivision === 3 ? selectedTabClasses : unselectedTabClasses}>
|
||||
Gold
|
||||
</a>
|
||||
<a href="#"
|
||||
onClick={e => {e.preventDefault(); setSelectedDivision(4)}}
|
||||
<a href="?division=4"
|
||||
onClick={e => {e.preventDefault(); handleDivisionChange(4)}}
|
||||
className={selectedDivision === 4 ? selectedTabClasses : unselectedTabClasses}>
|
||||
Platinum
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<ol className="list-decimal list-inside py-8 px-8 text-lg space-y-1">
|
||||
{module.map(m => (
|
||||
<li>
|
||||
<Link className="ml-2 text-blue-600 underline" to={m.node.frontmatter.slug}>{m.node.frontmatter.title}</Link>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{selectedDivision === 0 && introModules.map(renderModule)}
|
||||
{selectedDivision === 1 && bronzeModules.map(renderModule)}
|
||||
{selectedDivision === 2 && silverModules.map(renderModule)}
|
||||
{selectedDivision === 3 && goldModules.map(renderModule)}
|
||||
{selectedDivision === 4 && platModules.map(renderModule)}
|
||||
{module.map(renderModule)}
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
|
|
@ -21,10 +21,15 @@ export default function Template({
|
|||
const { htmlAst } = markdownRemark;
|
||||
const prereqs = markdownRemark.frontmatter.prerequisites;
|
||||
|
||||
let division = 0;
|
||||
if (markdownRemark.frontmatter.slug.includes("/bronze/")) division = 1;
|
||||
if (markdownRemark.frontmatter.slug.includes("/silver/")) division = 2;
|
||||
if (markdownRemark.frontmatter.slug.includes("/gold/")) division = 3;
|
||||
if (markdownRemark.frontmatter.slug.includes("/plat/")) division = 4;
|
||||
return (
|
||||
<Layout>
|
||||
<div className="max-w-4xl mx-auto my-8">
|
||||
<Link className="underline text-blue-600" to="/">← Back to Home</Link>
|
||||
<Link className="underline text-blue-600" to={"/?division="+division}>← Back to Home</Link>
|
||||
<h1 className="mt-8 text-3xl font-bold">{markdownRemark.frontmatter.title}</h1>
|
||||
<p className={`${prereqs ? "mb-4" : "mb-8"} text-gray-500`}>Author: {markdownRemark.frontmatter.author}</p>
|
||||
|
||||
|
|
Reference in a new issue