Codeforces-1313C2-Skyscrapers (hard version)(单调栈)

题目链接

题意

大小为n的数组表示摩天大楼的最大层数,要一个单峰的序列,求n栋楼的层数总和的最大值。

思路

easy版本可以用n2的方法,选取顶峰,然后求层数。

用单调栈可以O(n)解决。

单调栈基本思路讲解

大概就是,用单调栈,就可以用O(n)的复杂度解决,数组向左(右)遍历,第一个比它小(大)的值。所以给一个数组a[n],就可以得到比a[i]小,在 i 的左边且位置离 i 最近的a[j],可以把这个位置存到一个数组中。

用O(n)得到这个数组之后,对这个题来看,用dp的思想,得到一个前缀 l [n]的东西,表示以 i 为顶峰,左边的最大层数是多少。

求 l [i] ,找到比 a[i] 小的第一个数,位置是t,那么t前面这t个数就一定是可以的,因为是递增。

然后只需要把t到i中间这些数降低成为a[i]就可以(a[n]是楼的最高层数)

转移方程就是 l[i] = l[t] + (i-t) * a[i] 

这只是求出来了峰值左边的最大,右边同理。然后走一遍求一下峰值在哪里总和最大就可以了。

代码参考


#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f

using namespace std;

const int N = 5e5+10;

ll l[N],r[N],st[N],k;
int n,a[N];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);

    k = 0;
    for(int i=1;i<=n;i++){
        while(k!=0&&a[st[k]]>a[i]) k--;
        int t;
        if(k==0) t = 0;
        else t = st[k];
        l[i] = l[t] + 1ll*a[i]*(i-t);
        st[++k] = i;
    }

    k = 0;
    for(int i=n;i>=1;i--){
        while(k!=0&&a[st[k]]>a[i]) k--;
        int t;
        if(k==0) t = n+1;
        else t = st[k];
        r[i] = r[t] + 1ll*a[i]*(t-i);
        st[++k] = i;
    }

    ll mmax = 0; int p;
    for(int i=1;i<=n;i++){
        ll t = l[i] + r[i] - a[i];
        if(t>mmax){
            mmax = t;
            p = i;
        }
    }

    for(int i=p-1;i>=1;i--) a[i] = min(a[i],a[i+1]);
    for(int i=p+1;i<=n;i++) a[i] = min(a[i],a[i-1]);

    for(int i=1;i<=n;i++) printf("%d ",a[i]);

    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章