USACO 2018 December · Bronze · all three problems

← Full December 2018 set · Official results

Source. Statements and constraints below are paraphrased from usaco.org/index.php?page=dec18results. Each problem heading links to the canonical statement on usaco.org. Code is my own reference C++ — cross-check the official editorial before trusting it under contest pressure.

Problem 1 — Mixing Milk

Statement

Three buckets each have a capacity ci and an initial milk amount mi. Farmer John performs 100 pours in cyclic order: pour 1 sends bucket 1 into bucket 2, pour 2 sends bucket 2 into bucket 3, pour 3 sends bucket 3 into bucket 1, and so on. Each pour transfers as much milk as possible until the source empties or the destination fills. Output the milk amounts after all 100 pours.

Constraints

Key idea

Pure simulation. For each pour, the amount moved is min(source, destination_capacity − destination). No clever observation needed — 100 iterations is trivially fast.

Complexity target

O(1) — exactly 100 pours regardless of input.

Reference solution (C++)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    array<ll, 3> cap{}, milk{};
    for (int i = 0; i < 3; ++i) cin >> cap[i] >> milk[i];

    for (int step = 0; step < 100; ++step) {
        int a = step % 3;            // source
        int b = (step + 1) % 3;      // destination
        ll move = min(milk[a], cap[b] - milk[b]);
        milk[a] -= move;
        milk[b] += move;
    }
    for (int i = 0; i < 3; ++i) cout << milk[i] << "\n";
}

Pitfalls

Problem 2 — The Bucket List

Statement

Farmer John has N cows. Cow i needs to be milked from time si to time ti (inclusive on the open interval [si, ti)) and requires bi buckets during that window. Buckets can be reused once a cow finishes. Find the minimum total number of buckets Farmer John needs.

Constraints

Key idea

Classic sweep-line / difference array. At time si, add bi; at time ti, subtract bi. The answer is the maximum prefix sum. Equivalently: for each time t in [1, 1000], sum bi over cows whose interval contains t, and take the max.

Complexity target

O(T + N) where T = 1000. Even O(N·T) = 105 brute-force is fine.

Reference solution (C++)

#include <bits/stdc++.h>
using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int N; cin >> N;
    const int T = 1002;
    vector<int> diff(T + 2, 0);
    for (int i = 0; i < N; ++i) {
        int s, t, b; cin >> s >> t >> b;
        // Cow occupies [s, t]; she releases buckets at t+1 (or use [s, t) — see pitfalls).
        diff[s]     += b;
        diff[t + 1] -= b;
    }
    int cur = 0, ans = 0;
    for (int i = 1; i < T; ++i) {
        cur += diff[i];
        ans = max(ans, cur);
    }
    cout << ans << "\n";
}

Pitfalls

Problem 3 — Back and Forth

Statement

Each barn starts with 1000 gallons and 10 buckets (sizes given). On four consecutive days Farmer John walks one bucket between the barns: Tue barn 1 → 2, Wed barn 2 → 1, Thu barn 1 → 2, Fri barn 2 → 1. On each trip he fills the chosen bucket from the source tank and empties it into the destination tank (the bucket is then in the destination barn's closet for future trips). Output the number of distinct amounts of milk barn 1 can have on Saturday morning.

Constraints

Key idea

Brute-force DFS over the four trips. State after each trip is determined by (barn-1 tank, which buckets are at each barn). But because tank amounts depend only on signed sums of bucket sizes, you can collapse state to the running barn-1 amount and the multisets at each barn. Insert each final barn-1 value into a set<int>; output its size.

Complexity target

O(104) DFS leaves; each operation is an O(1) multiset swap. Fits in well under 1s.

Reference solution (C++)

#include <bits/stdc++.h>
using namespace std;

set<int> results;
vector<int> A, B;  // buckets currently at barn 1, barn 2

// day = 0..3; direction[d] = source barn (0 -> 1, 1 -> 0, 0 -> 1, 1 -> 0)
const int dir[4] = {0, 1, 0, 1};

void dfs(int day, int milk1) {
    if (day == 4) { results.insert(milk1); return; }
    vector<int>& src = (dir[day] == 0) ? A : B;
    vector<int>& dst = (dir[day] == 0) ? B : A;
    int sign = (dir[day] == 0) ? -1 : +1;  // barn-1 change

    for (int i = 0; i < (int)src.size(); ++i) {
        int bucket = src[i];
        src.erase(src.begin() + i);
        dst.push_back(bucket);
        dfs(day + 1, milk1 + sign * bucket);
        dst.pop_back();
        src.insert(src.begin() + i, bucket);
    }
}

int main() {
    A.resize(10); B.resize(10);
    for (auto& x : A) cin >> x;
    for (auto& x : B) cin >> x;
    dfs(0, 1000);
    cout << results.size() << "\n";
}

Pitfalls

What Bronze December 2018 was actually testing