APIO 2017 - Koala Game

Author: Andi Qu

Subtask 1

Assign a single stone to the first cup. The minimum cup is the one where Koala doesn't have a majority.

1int minValue(int N, int W) {
2 fill(B, B + N, 0);
3 B[0] = 1;
4 playRound(B, R);
5 if (R[0] < 2) return 0;
6 else for (int i = 1; i < N; i++) if (!R[i]) return i;
7}

Uses 1 turn.

Subtask 2

Binary search for the maximum value.

Assume we have a list of possible candidates for the maximum. Let this list be of length . Assign each candidate stones. Koala will always assign her stones so that the maximum cup gets a majority.

1int maxValue(int N, int W) {
2 vector<int> v;
3 for (int i = 0; i < N; i++) v.push_back(i);
4 while (v.size() != 1) {
5 int k = W / v.size();
6 fill(B, B + N, 0);
7 for (int i : v) B[i] = k;
8 playRound(B, R);
9 v.clear();
10 for (int i = 0; i < N; i++) if (R[i] > k) v.push_back(i);

Uses 4 turns.

Subtask 3

Assign cups 0 and 1 stones until Koala treats them differently, at which point we can tell which is greater.

We can binary search for : if both 0 and 1 get more than stones, increase and otherwise, decrease .

Since , the maximum value of we need to try is 9, which improves our binary search significantly.

1int greaterValue(int N, int W) {
2 int l = 1, r = 9;
3 while (l != r) {
4 int mid = (l + r) / 2;
5 B[0] = B[1] = mid;
6 playRound(B, R);
7
8 if (R[0] > mid && R[1] > mid) l = mid + 1;
9 else if (R[0] <= mid && R[1] <= mid) r = mid - 1;
10 else return (R[0] < R[1]);

Uses 3 turns.

Subtask 4

First, notice how . This suggests that we need a mergesort-like strategy.

Since we have 200 stones at our disposal this time, we can use one turn to compare two cups by assigning 100 stones to both of them and 0 stones to the other cups. Since we can compare cups efficiently, we can then use mergesort to find the values of each cup.

1inline bool compare(int a, int b, int N, int W) {
2 fill(B, B + N, 0);
3 B[a] = B[b] = W;
4 playRound(B, R);
5 return (R[b] > W);
6}
7vector<int> mergesort(vector<int> v, int N, int W) {
8 if (v.size() == 1) return v;
9
10 vector<int> a, b;

Uses fewer than 700 turns.

Subtask 5

We use a recursive strategy that solves for a known range in exactly moves by splitting into and for some in exactly 1 move.

Assign each cup we know to be in stones and then check which positions Koala has placed more than stones next to after the round. We can then find from this information, which will always be in the range .

1void split(vector<int> v, int N, int W, int* P, int l = 1, int r = 100) {
2 if (l == r) P[v[0]] = l;
3 else {
4 int x = min((int)sqrt(2 * l), W / (r - l + 1));
5
6 fill(B, B + N, 0);
7 for (int i : v) B[i] = x;
8
9 playRound(B, R);
10 vector<int> less, greater;

Uses 99 turns.

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!

Give Us Feedback on APIO 2017 - Koala Game!