题解:P10318 [SHUPC 2024] 彭罗斯水槽
Populus_euphratica · · 题解
首先来处理环形排列的问题,这个只用把数组复制一遍即可。
接着,考虑如何求解。
先来看一种情况(如下图所示)
黄色部分在箭头所指的位置贡献会消失。
正着考虑有多少贡献太难了,不如反着考虑在哪些时刻会有贡献消失。
考虑如何求出黄色的部分。
可以设一个数组
所以,就是
那么黄色部分的长度就是
那么
那么长度知道了,高度怎么求呢?
发现高度就是
最后答案可以做两边前缀和得到。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Maxn = 200010;
int n;
int Min, sum;
int ans[Maxn];
int a[Maxn], l[Maxn], r[Maxn];
int stk[Maxn], tot;
signed main(){
ios::sync_with_stdio(false);
cin >> n;
for(int i = 1 ; i <= n ; i++) cin >> a[i];
for(int i = n + 1 ; i <= 2 * n ; i++) a[i] = a[i - n];
for(int i = 1 ; i <= 2 * n ; i++){
while(a[i] <= a[stk[tot]] && tot) tot--;
l[i] = stk[tot];
stk[++tot] = i;
}
tot = 0;
for(int i = 2 * n ; i ; i--){
while(a[i] < a[stk[tot]] && tot) tot--;
r[i] = stk[tot];
stk[++tot] = i;
}
a[Min] = 1e18;
for(int i = 1 ; i <= n ; i++){
if(a[i] < a[Min]) Min = i;
sum += a[i];
}
for(int i = Min + 1 ; i <= Min + n ; i++){
if(a[i] == a[Min]) continue;
int x = r[i] - l[i] - 1;
int y = a[i] - max(a[l[i]], a[r[i]]);
// cout << i << " " << a[i] << " " << x << " " << y << '\n';
ans[1] += y;
ans[1 + x] -= y;
}
for(int i = 1 ; i <= n ; i++) ans[i] += ans[i - 1];
for(int i = 1 ; i <= n ; i++) ans[i] += ans[i - 1];
for(int i = 1 ; i <= n ; i++) cout << sum - ans[i] << " ";
cout << '\n';
return 0;
}