Codeforces Round #622 (Div. 2)C2
题意
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+10; 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=1;i<=n;i++){scanf("%lld",&a[i]);} for(it i=1;i<=n;i++){ while(st.size()&&a[st.top()]>=a[i]){st.pop();} if(st.empty()){minl[i]=0;} else{minl[i]=st.top();} st.push(i); } while(st.size()){st.pop();} for(it i=n;i>=1;i--){ while(st.size()&&a[st.top()]>=a[i]){st.pop();} if(st.empty()){minr[i]=n+1;} else{minr[i]=st.top();} st.push(i); } for(it i=1;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>=1;i--){ if(minr[i]==n+1){sumr[i]=(ll)(minr[i]-i)*a[i];} else{ sumr[i]=sumr[minr[i]]+(ll)(minr[i]-i)*a[i]; } } ll ans=-1;int pos; for(it i=1;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+1;i<=n;i++){ if(a[i]<zhi){ zhi=a[i]; } b[i]=zhi; } zhi=a[pos]; for(it i=pos-1;i>0;i--){ if(a[i]<zhi){ zhi=a[i]; } b[i]=zhi; } for(it i=1;i<=n;i++){ printf(i==n?"%lld\n":"%lld ",b[i]); } return 0; }