Codeforces Round #622 (Div. 2) C2. Skyscrapers (hard version)(单调栈)

题目链接
在这里插入图片描述
在这里插入图片描述
思路:如果要满足题意的话构造出来的序列一定是一个峰的形式,可是我们不知道峰点在哪儿?那就一个个枚举峰点,left【i】表示在1-i中比a【i】小的数的前缀和,right【i】表示i到n的比a【i】小的数的前缀和,求出这两个数组我们就可以知道如果i为峰点的话序列和,取最大值就可以了,最后要注意到一下算以i为峰点的序列和的时候别忘了要减去a【i】,因为有算重复了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+1;
stack<ll>s;
ll a[maxn],Left[maxn],Right[maxn],ans[maxn],maxx=0;
int main()
{
	int n,k;
	scanf("%d",&n);
	s.push(0);
	for(int i=1;i<=n;++i)
	{
		scanf("%lld",&a[i]);
		while(s.size()&&a[s.top()]>=a[i]) s.pop();
		Left[i]=Left[s.top()]+(i-s.top())*a[i];
		s.push(i);
	}
	while(!s.empty()) s.pop();
	s.push(n+1);
	for(int i=n;i>=1;--i) 
	{
		while(s.size()&&a[s.top()]>=a[i]) s.pop();
		Right[i]=Right[s.top()]+(s.top()-i)*a[i];
		s.push(i);
	}
	for(int i=1;i<=n;++i)
	if(Left[i]+Right[i]-a[i]>maxx) maxx=Left[i]+Right[i]-a[i],k=i;
	ans[k]=a[k];
	for(int i=k-1;i>=1;--i)
	ans[i]=min(a[i],ans[i+1]);
	for(int i=k+1;i<=n;++i)
	ans[i]=min(a[i],ans[i-1]);
	for(int i=1;i<=n;++i) printf("%lld ",ans[i]);
 } 
发布了144 篇原创文章 · 获赞 0 · 访问量 4933

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/104545277