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;
}

 

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