Loading

P10194 [USACO24FEB] Milk Exchange G 做题记录

思路(暴力 1)

我们可以先想一个最简单的暴力:遍历每一秒,每一秒的时候遍历每个奶牛来模拟题意。

但是发现这样的暴力没有优化的前景,考虑换一种暴力。

思路(暴力 2)

可以先假设每个奶牛的容量都一样大,那么所有奶牛都不会溢出,由此可以猜测第 i 秒溢出的数量就是前面 i 个奶牛的最小值减去目前这个奶牛的容量,由此可以写出第二个暴力,但是这个暴力和第一个暴力的区别在于这个每次查询是静态的,不像第一种暴力是动态的,可以考虑如何优化。

正解

我们可以通过单调队列得出每个奶牛在的最大的区间使得这个奶牛是这个区间的最小值。

那么由此就可以直接优化了,只不过要注意的是如果两个奶牛的容量同样是一个区间的最小值,我们可以采用单调队列一边是找到第一个小于目前值的,另一边是找到第一个小于等于目前值的,这样就可以解决这种问题。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
/*
*/
int n, a[1000005], d[1000005], sum, m[1000005];
int lowbit(int x) {
    return x & (-x);
}
int t[1000005], t2[1000005];
void addmax(int x, int y) {
    a[x] = y;
    for (int i = x; i <= n * 2; i += lowbit(i)) {
        t[i] = a[i];
        for (int j = 1; j < lowbit(i); j *= 2) {
            t[i] = min(t[i], t[i - j]);
        }
    }
}
int qmin(int l, int r) {
    int maxn = 1e18;
    while (l <= r) {
        maxn = min(maxn, a[r]);
        r --;
        for (; r - lowbit(r) >= l; r -= lowbit(r)) {
            maxn = min(maxn, t[r]);
        }
    } 
    return maxn;
}
int r[1000005], l[1000005], d2[1000005];
int s[1000005];
signed main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    memset(t, 0x7f, sizeof t);
    for (int i = 1; i <= n; i ++) cin >> a[i], sum += a[i], m[i] = a[i], addmax(i, a[i]);
    a[n + 1] = a[1];
    a[0] = a[n];
    // for (int i = 1; i <= n; i ++) d[i] = a[i];
    // d[0] = a[n];
    for (int i = n + 1; i <= 2 * n; i ++) a[i] = a[i - n], m[i] = m[i - n], addmax(i, a[i]);
    for (int i = 1; i <= n * 2; i ++) s[i] = s[i - 1] + a[i];
    stack <int> st;
    for (int i = n * 2; i >= 1; i --) {
        while (st.size() && a[st.top()] >= a[i]) st.pop();
        if (st.size()) r[i] = st.top();
        else r[i] = n * 2 + 1;
        st.push(i);
    }
    while (st.size()) st.pop();
    for (int i = 1; i <= n * 2; i ++) {
        while (st.size() && a[st.top()] > a[i]) st.pop();
        if (st.size()) l[i] = st.top();
        else l[i] = 0;
        st.push(i);
    }
    int pos = 0;
    a[pos] = 1e18;
    for (int i = 1; i <= n; i ++) if (a[i] < a[pos]) pos = i;
    for (int i = pos + 1; i <= pos + n; i ++) {
        if (r[i] != 2 * n + 1 && a[i] != a[pos]) {
            int ll = r[i] - i;
            int rr = r[i] - l[i];

            // cout << i << " " << ll << " " << rr << "\n";
            d2[ll] += a[i] - a[r[i]];
            d2[rr] -= a[i] - a[r[i]];
        } 
    }
    // cout << endl;
    // for (int i = pos + 1; i <= pos + n; i ++) {
        // if (a[i] <= a[pos]) continue;
        // cout << i << " " << 1 << " " << (r[i] - l[i] - 1 + 1) << "\n";
        // if (r[i] != n * 2 + 1) {
        //     d2[1] += a[i] - max(a[l[i]], a[r[i]]);
        //     d2[(r[i] - l[i] - 1) + 1] -= a[i] - max(a[l[i]], a[r[i]]);
        // }
    // }
    for (int i = 1; i <= n; i ++) {
        d[i] = 0;
        d[i] = d[i - 1] + d2[i];
    }
    for (int i = 1; i <= n; i ++) {
        m[i] = 0;
        m[i] = m[i - 1] + d[i];
    }
    for (int i = 1; i <= n; i ++) {
        cout << sum - m[i] << "\n";
    }
    // cout << qmin(1, 3) << "\n";
    // for (int j = 1; j <= n; j ++) {
    //     for (int i = n + 1; i <= n * 2; i ++) {
    //         // cout << i << " " << a[i] << " " << j << "\n";
    //         int minn = 1e18;
    //         // for (int k = i - j; k < i; k ++) {
    //         //     minn = min(minn, m[k]);
    //         // }
    //         minn = qmin(i - j, i - 1);
    //         // cout << minn << "\n";
    //         if (minn > m[i]) {
    //             sum -= (minn - m[i]);
    //             // a[i] = m[i];
    //         }
    //         else {
    //             // a[i] = d[i - 1];
    //         }
    //     }
    //     // for (int i = n + 1; i <= n * 2; i ++) d[i] = a[i];
    //     // for (int i = 1; i <= n; i ++) a[i] = a[i + n], d[i] = d[i + n];
    //     cout << sum << "\n";
    // }
    
    return 0;
}
posted @ 2025-11-09 17:11  ztrztr  阅读(6)  评论(0)    收藏  举报