有 (n) 个位置,分别在上面盖楼,第 (i) 个不能超过 (m_i) 层,对任意一栋楼,它的左边所有楼中和右边所有楼中,不能都有比它高的楼,求最大化楼层总数和的方案
Solution
Easy:暴力枚举峰在哪,然后向两侧递推过去即可
Hard:既然都单调了,用单调栈维护一下单向的前缀/后缀答案,然后枚举峰位置拼起来即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 500005;
int n,m[N],pos[N],a[N],sta[N],top,sum,ans1[N],ans2[N],x,ans;
signed main() {
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>m[i];
top=0; sum=0;
for(int i=1;i<=n;i++) {
while(top && m[i]<sta[top]) {
sum-=(pos[top]-pos[top-1])*sta[top];
--top;
}
++top;
pos[top]=i;
sta[top]=m[i];
sum+=(pos[top]-pos[top-1])*sta[top];
ans1[i]=sum;
}
reverse(m+1,m+n+1);
top=0; sum=0;
for(int i=1;i<=n;i++) {
while(top && m[i]<sta[top]) {
sum-=(pos[top]-pos[top-1])*sta[top];
--top;
}
++top;
pos[top]=i;
sta[top]=m[i];
sum+=(pos[top]-pos[top-1])*sta[top];
ans2[i]=sum;
}
reverse(m+1,m+n+1);
reverse(ans2+1,ans2+n+1);
for(int i=1;i<=n;i++) {
int tmp=ans1[i]+ans2[i]-m[i];
if(tmp>ans) {
ans=tmp;
x=i;
}
}
{
int i=x;
a[i]=m[i];
for(int j=i-1;j;j--) {
a[j]=min(a[j+1],m[j]);
}
for(int j=i+1;j<=n;j++) {
a[j]=min(a[j-1],m[j]);
}
for(int j=1;j<=n;j++) cout<<a[j]<<" ";
}
}