Codeforces Round #622 (Div. 2) 比赛人数5752
[codeforces 1313C2] Skyscrapers (hard version) 单调栈+变化量的和+俄罗斯方块
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址https://codeforces.ml/contest/1313/problem/C2
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
C2 - Skyscrapers (hard version) | GNU C++11 | Accepted | 233 ms | 13500 KB |
合理的数据,是一座山峰,若有不明,请看此文[codeforces 1313C1] Skyscrapers (easy version) 问的是谷,答的是峰
//单调栈
//i位置是峰,f[i]是峰左侧的变化量,g[i]是峰右侧的变化量
//求得是f[i]+g[i]对应最小值时的数据
算法详见,数据模拟
5
1 2 3 2 1
1 2 3 2 1
5
1 2 3 2 1
1 2 3 4 5
i=1,
原始1 2 3 2 1
结束1 1 1 1 1
变化0 1 2 1 0
变化量f[1]=0,g[1]=1+2+1+0=4,f[1]+g[1]=4
i=2,
原始1 2 3 2 1
结束1 2 2 2 1
变化0 0 1 0 0
变化量f[2]=0,g[2]=1+0+0=1,f[2]+g[2]=1
i=3,
原始1 2 3 2 1
结束1 2 3 2 1
变化0 0 0 0 0
变化量f[3]=0,g[3]=0+0+0=0,f[3]+g[3]=0
依次类推...
再结合代码,相信读者一定能弄懂。
AC代码如下
#include <cstdio>
#include <algorithm>
#define maxn 500010
#define LL long long
using namespace std;
int sta[maxn],stb[maxn],top,a[maxn],tot;
LL f[maxn],g[maxn];
int main(){
int i,n,ans;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
top=0;
for(i=1;i<=n;i++){//i位置数据作为峰
f[i]=f[i-1],tot=1;//tot记录栈中stb[top-1]<j<=stb[top],a[j]>=a[i]数据的数量
while(top&&a[sta[top]]>=a[i]){
f[i]+=(LL)(a[sta[top]]-a[i])*stb[top];//有点象俄罗斯方块,一层一层的消
tot+=stb[top],top--;
}
top++,sta[top]=i,stb[top]=tot;
}
top=0;
for(i=n;i>=1;i--){//i位置数据作为峰
g[i]=g[i+1],tot=1;//tot记录栈中stb[top-1]<j<=stb[top],a[j]>=a[i]数据的数量
while(top&&a[sta[top]]>=a[i]){
g[i]+=(LL)(a[sta[top]]-a[i])*stb[top];
tot+=stb[top],top--;
}
top++,sta[top]=i,stb[top]=tot;
}
ans=1;
for(i=1;i<=n;i++)
if(f[i]+g[i]<f[ans]+g[ans])ans=i;
for(i=ans-1;i>=1;i--)a[i]=min(a[i],a[i+1]);//峰左侧的数据生成
for(i=ans+1;i<=n;i++)a[i]=min(a[i],a[i-1]);//峰右侧的数据生成
for(i=1;i<n;i++)printf("%d ",a[i]);
printf("%d\n",a[n]);
return 0;
}