1 条题解

  • 0
    @ 2026-5-5 22:44:44

    考虑断环成链,然后求出每个位置左边第一个比他小的数的位置 lil_i 和右边第一个不超过他的数的位置 rir_i,这里可以使用单调栈。

    显然第 ii 个位置对失去牛奶的贡献就是在 [1,rili1][1, r_i - l_i - 1] 这几秒中,失去一个初始值和公差都是 aimax(ali,ari)a_i - max(a_{l_i}, a_{r_i}) 的等差数列,然后在之后的所有时间失去等差数列的末项个单位的牛奶。

    这是一个经典 trick,使用差分数组的差分维护即可,实现细节见参考代码。时间复杂度 O(n)\mathcal{O}(n)

    参考代码:

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    inline int read(){
    	int x = 0, f = 1;
    	char ch = getchar();
    	while(!isdigit(ch)){
    		if(ch == '-') f = -1;
    		ch = getchar();
    	}
    	while(isdigit(ch)){
    		x = (x << 1) + (x << 3) + (ch ^ 48);
    		ch = getchar();
    	}
    	return x * f;
    }
    
    int n, a[1000005], l[1000005], r[1000005], d[1000005], sum = 0;
    signed main(){
        n = read();
    	for(int i = 1; i <= n; i++) sum += (a[i] = a[i + n] = read());
    
    	stack<int> s;
    	for(int i = 1; i <= n + n; i++){
    		while(!s.empty() && a[s.top()] >= a[i]) s.pop();
    		l[i] = s.empty() ? 0 : s.top();
    		s.push(i);
    	}
    	while(!s.empty()) s.pop();
    	for(int i = n + n; i >= 1; i--){
    		while(!s.empty() && a[s.top()] > a[i]) s.pop();
    		r[i] = s.empty() ? n + 1 : s.top();
    		s.push(i);
    	}
    
    	int Minid = 0; a[0] = INT_MAX;
    	for(int i = 1; i <= n; i++) if(a[i] < a[Minid]) Minid = i;
    	// for(int i = Minid + 1; i <= Minid + n; i++) cout << l[i] << ' ' << r[i] << '\n';
    
    	for(int i = Minid + 1; i <= Minid + n; i++) if(a[i] > a[Minid]){
    		int L = 1, R = r[i] - l[i] - 1;
    		int A = a[i] - max(a[l[i]], a[r[i]]), D = A;
    		// cout << i << ": " << L << ' ' << R << ' ' << A << '\n';
    		d[L] += A, d[L + 1] += D - A, d[R + 1] -= D;
    	}
    
    	for(int i = 1; i <= n; i++) d[i] += d[i - 1];
    	for(int i = 1; i <= n; i++) cout << sum - (d[i] += d[i - 1]) << '\n';
        return 0;
    }
    
    • 1

    信息

    ID
    7614
    时间
    2000ms
    内存
    256MiB
    难度
    8
    标签
    递交数
    14
    已通过
    6
    上传者