题意
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];
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define il inline 5 #define it register int 6 #define inf 0x3f3f3f3f 7 #define lowbit(x) (x)&(-x) 8 #define mem(a,b) memset(a,b,sizeof(a)) 9 #define modd 998244353 10 const int maxn=5e5+10; 11 int n; 12 ll a[maxn],b[maxn],minl[maxn],minr[maxn],suml[maxn],sumr[maxn]; 13 stack<int>st; 14 int main(){ 15 scanf("%d",&n); 16 for(it i=1;i<=n;i++){scanf("%lld",&a[i]);} 17 for(it i=1;i<=n;i++){ 18 while(st.size()&&a[st.top()]>=a[i]){st.pop();} 19 if(st.empty()){minl[i]=0;} 20 else{minl[i]=st.top();} 21 st.push(i); 22 } 23 while(st.size()){st.pop();} 24 for(it i=n;i>=1;i--){ 25 while(st.size()&&a[st.top()]>=a[i]){st.pop();} 26 if(st.empty()){minr[i]=n+1;} 27 else{minr[i]=st.top();} 28 st.push(i); 29 } 30 for(it i=1;i<=n;i++){ 31 if(!minl[i]){suml[i]=(ll)i*a[i];} 32 else{ 33 suml[i]=suml[minl[i]]+(ll)(i-minl[i])*a[i]; 34 } 35 } 36 for(it i=n;i>=1;i--){ 37 if(minr[i]==n+1){sumr[i]=(ll)(minr[i]-i)*a[i];} 38 else{ 39 sumr[i]=sumr[minr[i]]+(ll)(minr[i]-i)*a[i]; 40 } 41 } 42 ll ans=-1;int pos; 43 for(it i=1;i<=n;i++){ 44 ll zz=sumr[i]+suml[i]-a[i]; 45 //cout<<sumr[i]<<" "<<minr[i]<<" "<<suml[i]<<endl; 46 if(zz>ans){ 47 ans=zz,pos=i; 48 } 49 } 50 51 b[pos]=a[pos];ll zhi=a[pos]; 52 for(it i=pos+1;i<=n;i++){ 53 if(a[i]<zhi){ 54 zhi=a[i]; 55 } 56 b[i]=zhi; 57 } 58 zhi=a[pos]; 59 for(it i=pos-1;i>0;i--){ 60 if(a[i]<zhi){ 61 zhi=a[i]; 62 } 63 b[i]=zhi; 64 } 65 for(it i=1;i<=n;i++){ 66 printf(i==n?"%lld\n":"%lld ",b[i]); 67 } 68 return 0; 69 }
原文地址:https://www.cnblogs.com/luoyugongxi/p/12356639.html
时间: 2024-11-01 16:23:51