USACO Gold 2019 Open - I Would Walk 500 Miles
Authors: Benjamin Qi, Aryansh Shrivastava, Chuyang Wang
Solution 1: Prim's Algorithm
For this problem, we want to maximize the minimum of the number of miles two cows are willing to walk, henceforth referred to as . Let's consider a Minimum Spanning Tree (MST) of all cows. By adding the -th edge to the MST, it implies that all edges between the rest components have weights higher or equal than this added edge, or, in other words, is equal to the weight of this added edge.
In case of splitting the cows into groups, we remove the edges from the MST which have the maximum weight. is then equal to the weight of the minimum of those removed edges. If the edges in the MST are sorted in ascending order, would be the weight of the -th edge of the MST.
As the typical implementation of Kruskal's Algorithm requires time for a dense graph as in our case, we use instead Prim's Algorithm with linear search for the closest vertex. Each scan only takes time, and we only have to do scans.
Time Complexity:
C++
#include <bits/stdc++.h>using namespace std;using ll = long long;const ll MOD = 2019201997LL;const ll FACTOR1 = 2019201913LL;const ll FACTOR2 = 2019201949LL;/*** @return the number of miles cow a + 1 and b + 1 are willing to walk to see
Java
import java.io.*;import java.util.*;public class Walk {static final long MOD = 2019201997L;static final long FACTOR1 = 2019201913L;static final long FACTOR2 = 2019201949L;public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("walk.in"));
Solution 2: Kruskal's Algorithm & Two-Pass Radix Sort
Alternatively, we can also use Kruskal's Algorithm to construct our MST. Note that only the step of sorting all edges takes too long time. If we manage to sort all edges in linear time, we might be able to solve it with Kruskal's Algorithm as well.
To sort these edges, we can apply a two-pass radix sort. In particular, we first use counting sort to sort the first 16 bits () of the weights. Then, in the second iteration, we sort the rest 16 bits (). After the sorting process, we apply the unmodified Kruskal's Algorithm on the edges and is equal to the weight of the -th longest edge of the MST.
Time Complexity:
Warning: TLE
Some large test cases might get TLE due to the bad constant factor for the radix sort.
C++
#include <bits/stdc++.h>using namespace std;using ll = long long int;Code Snippet: DSU (Click to expand)const ll MOD = 2019201997LL;const ll FACTOR1 = 2019201913LL;const ll FACTOR2 = 2019201949LL;
Solution 3: Math
Since this problem has its roots in optimizing a given weight expression, we are motivated to use math.
First, we can use modular arithmetic to find a direct expression for the modular residue. The goal is to find an expression for the modular residue involving only basic operations that we will be able to optimize with mathematical techniques. Using modular arithmetic properties (negative numbers in modular arithmetic), consider the expression to reduce the numbers:
Since are bounded by this expression will always give a negative value whose absolute value does not exceed the modulus Thus, we can easily find an expression for the modular residue from here if we just shift up by the modulus once:
Now, it remains to optimize this expression. Formally, we must find a -partition of the cows such that
is maximized.
Now, let's analyze the function's behavior: for large the expression becomes small, and for small the expression becomes large.
But remembering the condition that must be in different groups to contribute to the answer, this means that large should be together in the same group (to greedily avoid making the expression small) and small should be in different groups (to greedily make the expression large). This leads to the following greedy strategy:
Make one group with all the largest cows that can fit and groups with all the smallest cows. Of course, the smallest cows are just so this means that the other cows will be in the large group.
Now that we have pinpointed the optimal grouping, we can find the answer by going back to the question: we want to minimize the expression. To minimize the expression, we should greedily choose the largest cows that are in different groups (since large make the expression smaller). Clearly, this means that we should take cow the largest cow in the group of large cows, and the largest cow not in the group of large cows.
Recall that the problem statement requires so we have Our answer is as easy as a substitution of these values into the modular residue expression
In retrospect, this solution is equivalent to performing Kruskal's MST algorithm by hand when we analyze the edge weight expression and use greedy logic to create the optimal grouping. (So the previous solutions will find the exact same grouping.)
Time Complexity:
Senpat's implementation:
C++
#include <bits/stdc++.h>using namespace std;int main() {freopen("walk.in", "r", stdin);freopen("walk.out", "w", stdout);int N, K;cin >> N >> K;long long answer = 2019201997LL - 48LL * N - 84LL * (K - 1LL);cout << answer << endl;}
Java
import java.io.*;import java.util.*;public class Walk {public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new FileReader("walk.in"));StringTokenizer st = new StringTokenizer(br.readLine());br.close();int N = Integer.parseInt(st.nextToken());
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!