题目链接:https://codeforces.com/contest/1313/problem/C2
题意:n层楼,每层高度不超过m[i],要求最终楼的高度满足:不存在i<j<k,ai>aj<ak。求满足这个要求的楼高度和的最大值
设dpl[i]表示第i个建成最高高度m[i],左边的满足条件的最大高度和。显然左边的高度都不能高于m[i],如果高于m[i]就把它建成m[i]即可。于是可以找左边第一个<=m[i]的数的位置l[i],则有dpl[i]=dpl[l[i]]+(i-l[i])*m[i]。对于右边的dpr[i]同理。最终最大高度和为max(dpl[i]+dpr[i]-m[i])。确定了最大高度和的对应位置之后,求出一组解就很方便了。找左(右)第一个<=m[i]的数可以用单调栈O(n)实现,递推也是O(n),总时间复杂度O(n)
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=5e5+10; ll m[N],l[N],r[N],res[N],dpl[N],dpr[N],n,i,j; stack<int> st; int main(){ std::ios::sync_with_stdio(false); cin>>n; for (i=1;i<=n;i++) cin>>m[i]; m[0]=-1; m[n+1]=2e9; st.push(n+1); for (i=n;i>=0;i--){ while (!st.empty()&&m[i]<=m[st.top()]){ l[st.top()]=i; st.pop(); } st.push(i); } while (!st.empty()) st.pop(); m[n+1]=-1; m[0]=2e9; st.push(0); for (i=1;i<=n+1;i++){ while (!st.empty()&&m[i]<=m[st.top()]){ r[st.top()]=i; st.pop(); } st.push(i); } dpl[1]=m[1]; dpr[n]=m[n]; for (i=2;i<=n;i++) dpl[i]=dpl[l[i]]+(i-l[i])*m[i]; for (i=n-1;i>=1;i--) dpr[i]=dpr[r[i]]+(r[i]-i)*m[i]; int pos=0; ll ans=-1; for (i=1;i<=n;i++) if (dpl[i]+dpr[i]-m[i]>ans){ ans=dpl[i]+dpr[i]-m[i]; pos=i; } res[pos]=m[pos]; for (i=pos-1;i>=1;i--) res[i]=min(res[i+1],m[i]); for (i=pos+1;i<=n;i++) res[i]=min(res[i-1],m[i]); for (i=1;i<n;i++) cout<<res[i]<<' '; cout<<res[n]; return 0; }