题意

N长度为500000以内,一个数字两边的数字不能都比他高,最多高一边

求他最大sum。叙述有问题,直接看样例

3

10 6 8

因为6左右都比他高,选择10 6 6或者6 6  8,sum明显前者高

所以答案输出10 6 6

思路:

求出每个a[i]左边(minl[i])和右边(minl[i])最近的一个比他小的数,用前缀和(suml) 和 后缀和(sumr)求得当a[i]是顶点时候sum=suml+sumr-a[i];

前缀和如果minl[i]==空集(0),那么suml[i]=i*a[i];如果minl[i]有位置,suml[i]=suml[minl[i]]+(i-minl[i])*a[i];

后缀和如果minr[i]==空集(n+1),那么sumr[i]=(n+1-i)*a[i];如果minr[i]有位置,sumr[i]=sumr[minr[i]]+(minr[i]-i)*a[i];

 #include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define it register int
#define inf 0x3f3f3f3f
#define lowbit(x) (x)&(-x)
#define mem(a,b) memset(a,b,sizeof(a))
#define modd 998244353
const int maxn=5e5+;
int n;
ll a[maxn],b[maxn],minl[maxn],minr[maxn],suml[maxn],sumr[maxn];
stack<int>st;
int main(){
scanf("%d",&n);
for(it i=;i<=n;i++){scanf("%lld",&a[i]);}
for(it i=;i<=n;i++){
while(st.size()&&a[st.top()]>=a[i]){st.pop();}
if(st.empty()){minl[i]=;}
else{minl[i]=st.top();}
st.push(i);
}
while(st.size()){st.pop();}
for(it i=n;i>=;i--){
while(st.size()&&a[st.top()]>=a[i]){st.pop();}
if(st.empty()){minr[i]=n+;}
else{minr[i]=st.top();}
st.push(i);
}
for(it i=;i<=n;i++){
if(!minl[i]){suml[i]=(ll)i*a[i];}
else{
suml[i]=suml[minl[i]]+(ll)(i-minl[i])*a[i];
}
}
for(it i=n;i>=;i--){
if(minr[i]==n+){sumr[i]=(ll)(minr[i]-i)*a[i];}
else{
sumr[i]=sumr[minr[i]]+(ll)(minr[i]-i)*a[i];
}
}
ll ans=-;int pos;
for(it i=;i<=n;i++){
ll zz=sumr[i]+suml[i]-a[i];
//cout<<sumr[i]<<" "<<minr[i]<<" "<<suml[i]<<endl;
if(zz>ans){
ans=zz,pos=i;
}
} b[pos]=a[pos];ll zhi=a[pos];
for(it i=pos+;i<=n;i++){
if(a[i]<zhi){
zhi=a[i];
}
b[i]=zhi;
}
zhi=a[pos];
for(it i=pos-;i>;i--){
if(a[i]<zhi){
zhi=a[i];
}
b[i]=zhi;
}
for(it i=;i<=n;i++){
printf(i==n?"%lld\n":"%lld ",b[i]);
}
return ;
}
05-28 06:18