(Analysis by Chongtian Ma, Alex Liang, and Patrick Deng)

Subtask 1: $N \le 2000$.

We can directly simulate the process according to the problem statement. We can keep track of the amount of milk that each cow has and update in $\mathcal{O}(N)$ each minute leading to an $\mathcal{O}(N^2)$ solution.

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

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0); 
    int n;
    cin >> n;

    vector<int> cap(n), cur(n); 
    
    for (int i = 0; i < n; i++){
        cin >> cap[i];
        cur[i] = cap[i];
    }
    
    for (int minute = 1; minute <= n; minute++){
        rotate(cur.begin(), cur.begin() + n - 1, cur.end());

        for (int i = 0; i < n; i++)
            cur[i] = min(cur[i], cap[i]);

        cout<<accumulate(cur.begin(), cur.end(), 0LL)<<"\n";
    }
}

Subtask 2: $a_i \le 2$.

Each bucket has capacity of either $1$ or $2$ in this subtask. Consider a cow that starts off with $2$ unit of milk. That specific $2$ units of milk will keep getting passed until it reaches a bucket with capacity $1$ where it will be reduced to $1$ unit of milk.

For each $a_i=2$ we want to find the time $t$ in which it will reach a bucket with capacity $1$. Then we know that $1$ milk is lost at time $t$. We can find $t$ by finding the first $a_j=1$ on the right of $i$.

We can rotate the array such that the minimum element appears at the end. Iterating over the array backwards and keeping track of the most recent $1$ leads to an $\mathcal{O}(N)$ solution.

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

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0); 
    int n;
    cin >> n;

    vector<int> A(n); 
    vector<int> reduce(n + 5, 0);

    int sum = 0;

    for (int &i : A){
        cin >> i;
        sum += i;
    }
    rotate(A.begin(), next(min_element(A.begin(), A.end())), A.end());
    
    for (int i = n - 1, lst = -1; i >= 0; i--){
        if (A[i] == 1)
            lst = i;
        if (A[i] == 2 and lst != -1){
            // At time lst - i the 2 will get reduced to a 1
            reduce[lst - i]++;
        }
    }
    
    for (int i = 1; i <= n; i++){
        sum -= reduce[i];
        cout<<sum<<"\n";
    }
}

Subtask 3: All $a_i$ are generated uniformly at random in the range $[1,10^9]$.

Let's rotate the array such that the minimum element appears at the end.

In the previous subtask, for each $a_i=2$, we wanted to find when that specific $2$ units of milk will reach a bucket with capacity $1$. We can extend this reasoning. For some $a_i$, we want to find all times in which that milk will get reduced.

To find these values, we can iterate over the array backwards and keep a monotonic stack. At each element, we can iterate over the entire stack and update our answer.

Because all $a_i$ are generated uniformly at random, the expected size of the monotonic stack at each $i$ is $\mathcal{O}(\log N)$. This is since the probability of $j$ ($i \le j < i+N$) being in the stack is at most $\frac{1}{j-i+1}$ since $a_j$ must be smaller than $[a_i,a_{i+1},...,a_{j-1}]$. By the linearity of expectation, the expected size of the stack is $\frac{1}{1}+\frac{1}{2}+ \dots +\frac{1}{N}=\mathcal{O}(\log N)$ by the harmonic series. Thus, the solution runs in $\mathcal{O}(N\log N)$ time.

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

#define ll long long

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0); 
    int n;
    cin >> n;

    vector<int> A(n); 
    ll sum = 0;

    for (int &i : A){
        cin >> i;
        sum += i;
    }
    rotate(A.begin(), next(min_element(A.begin(), A.end())), A.end());

    vector<int> stk;
    vector<ll> reduce(n + 5, 0);

    auto procStack = [&](int pos){
        for (int i = 1; i < stk.size(); i++){
            int delta = A[stk[i]] - A[stk[i - 1]];
            reduce[stk[i - 1] - pos] += delta; 
        }
    };

    for (int i = n - 1; i >= 0; i--){
        while (stk.size() and A[stk.back()] >= A[i]){
            stk.pop_back();
        }
        stk.push_back(i);
        procStack(i);
    }

    for (int i = 1; i <= n; i++){
        sum -= reduce[i];
        cout<<sum<<"\n";
    }
}

Full Solution 1:

Let's look at what is redundant in our subtask $3$ solution. Suppose the bottom $2$ elements of the stack remain there for a long time. Then we will be iterating over them each time we process the stack.

Let's speed up our subtask $3$ solution. Consider some adjacent pair of elements ($j_{p-1},j_p$) in the stack. We know that $d=a_{j_{p-1}}-a_{j_p}$ milk is lost by going from $j_{p-1}$ to $j_p$. Let's look at all $i$ ($1 \le i \le N$) where ($j_{p-1},j_p$) is in the stack at $i$ (meaning the milk originating from $i$ will be reduced by $d$ at time $j_p-i$). Clearly, all such $i$ will form an interval.

When we remove an element from the top of the stack, we can get the interval it was active for and perform a range add to keep track of how much milk is lost at what time. This leads to an $\mathcal{O}(N)$ solution.

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

#define ll long long

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0); 
    int n;
    cin >> n;

    vector<int> A(n); 
    ll sum = 0;

    for (int &i : A){
        cin >> i;
        sum += i;
    }
    rotate(A.begin(), next(min_element(A.begin(), A.end())), A.end());

    vector<int> stk;
    vector<ll> reduce(n + 5, 0);

    for (int i = n - 1; i >= 0; i--){
        while (stk.size() and A[stk.back()] >= A[i]){
            if (stk.size() > 1){
                // i < t1 < t2
                int t1 = stk.back();
                int t2 = stk[stk.size() - 2];

                // Milk lost from going from t1 to t2
                int delta = A[t1] - A[t2];
                
                // When does the pair begin applying delta
                int st = t2 - t1;

                // For how long does the pair apply delta
                int sz = t1 - i;

                reduce[st] += delta;
                reduce[st + sz] -= delta;
            }
            stk.pop_back();
        }
        stk.push_back(i);
    }

    // Finish proccessing rest of stack
    while (stk.size() > 1){
        int t1 = stk.back();
        int t2 = stk[stk.size() - 2];

        int delta = A[t1] - A[t2];
        int st = t2 - t1;
        int sz = t1 + 1;

        reduce[st] += delta;
        reduce[st + sz] -= delta;

        stk.pop_back();
    }

    // Get answer
    for (int i = 1; i <= n; i++){
        reduce[i] += reduce[i - 1];
        sum -= reduce[i];

        cout<<sum<<"\n";
    }
}

Full Solution 2:

For each $i$, we want to find the number of buckets with milk $a_i$ at each minute. To deal with the case where there are multiple same $a_i$, we only consider the number of buckets equal to $a_i$ whose milk was specifically reduced (by a non-zero amount) to $a_i$ by the bucket at $i$ (we also count the milk starting at $i$).

Let $l_i$ be the index of the first element less than or equal to $a_i$ on the left of $i$. Consider all elements strictly between $l_i$ and $i$. All these elements will be greater than $a_i$ and thus will be reduced to $a_i$ when they reach $i$. Suppose there are $s$ such elements including $a_i$. Then we will gain one additional element equal to $a_i$ at times $0,1,...,s-1$ (if we suppose we start off with $0$ elements equal to $a_i$).

Let $w_i$ store the total amount of milk at time $i$. We should perform the following update:

We also know that buckets with $a_i$ milk can be reduced to a smaller value. Let $r_i$ be the index of the first element strictly less than $a_i$ on the right of $i$. Let time $t$ be the time for the milk originating at $i$ to reach $r_i$. Then we will lose one element equal to $a_i$ at times $t,t+1,...,t+s-1$. A similar update to the one above should be performed.

We can use a monotonic stack to find $l_i$ and $r_i$. Implementation can be made easier by prepending and appending the array to itself. We can use prefix sums of prefix sums to perform the updates on $w$ efficiently. See the following example:

Thus, this solution runs in $\mathcal{O}(N)$ time.

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

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0);
    int n;
    cin >> n;

    vector<int> A(n);

    for (int &i : A)
        cin >> i;
    
    for (int i = 0; i < 2 * n; i++)
        A.push_back(A[i]);
    
    // L is first <= on left and R is first < on right
    vector<int> L(A.size()), R(A.size());
    {
        stack<int> stk;
        for (int i = 0; i < A.size(); i++){
            while (stk.size() and A[i] < A[stk.top()])
                stk.pop();

            L[i] = stk.empty() ? -1 : stk.top();
            stk.push(i);
        }
    }
    {
        stack<int> stk;
        for (int i = (int)A.size() - 1; i >= 0; i--){
            while (stk.size() and A[i] <= A[stk.top()])
                stk.pop();
            
            R[i] = stk.empty() ? -1 : stk.top();
            stk.push(i);
        }
    }

    vector<ll> psm(n + 5, 0);

    for (int i = n; i < 2 * n; i++){
        // Gain A[i] during minutes [0, sz - 1]
        int sz = i - L[i];
        psm[0] += A[i];
        psm[sz] -= A[i];

        // Lose A[i] during minutes [R[i] - i, R[i] - i + sz - 1]
        if (R[i] != -1){
            psm[R[i] - i] -= A[i];
            psm[R[i] - i + sz] += A[i];
        }
    }

    for (int i = 1; i <= n; i++)
        psm[i] += psm[i - 1];

    for (int i = 1; i <= n; i++){
        psm[i] += psm[i - 1];
        cout<<psm[i]<<"\n";
    }
}