[CF1313C] Skyscrapers - 单调栈

\(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]<<" ";
    }
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12468242.html