题目链接
思路:如果要满足题意的话构造出来的序列一定是一个峰的形式,可是我们不知道峰点在哪儿?那就一个个枚举峰点,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]);
}