[codeforces 1313C2] Skyscrapers (hard version) 单调栈+变化量的和+俄罗斯方块

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;
}
发布了560 篇原创文章 · 获赞 536 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/mrcrack/article/details/104577372