codeforces 1313C2 Skyscrapers (hard version) 單調棧+dp

https://vjudge.net/problem/CodeForces-1313C2
在這裏插入圖片描述在這裏插入圖片描述思路:不難想到枚舉一個最高點ii,然後[1i][1…i]非降,[i,n][i,n]非升即可滿足題意。實際上這也是簡單版的做法。我們搞兩個數組lrl、rl[i]l[i]表示當[1i][1…i]非降時所能得到的最高分,r[i]r[i]表示當[in][i…n]非升時所能得到的最高分,那麼只需掃一遍數組取ans=max(ans,l[i]+r[i]m[i])ans=max(ans,l[i]+r[i]-m[i])即可。現在考慮怎麼計算這兩個數組,以ll爲例,假設l[1i]l[1…i]已知,如果m[i+1]>m[i]m[i+1]>m[i],顯然有l[i+1]=l[i]+m[i+1]l[i+1]=l[i]+m[i+1],否則我們找到<i+1<i+1的最大的jj,顯然有l[i+1]=l[j]+(i+1j)m[i+1]l[i+1]=l[j]+(i+1-j)*m[i+1]。通過單調棧就可以O(n)O(n)求得數組ll,數組rr同理。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pr pair<double,int>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

const int maxn=5e5+5;

int n;
ll a[maxn],l[maxn],r[maxn];
stack<int> s;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%I64d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        while(!s.empty()&&a[s.top()]>=a[i])
            s.pop();
        if(s.empty())
            l[i]=i*a[i];
        else
            l[i]=l[s.top()]+(i-s.top())*a[i];
        s.push(i);
    }
    while(!s.empty())
        s.pop();
    for(int i=n;i>=1;i--)
    {
        while(!s.empty()&&a[s.top()]>=a[i])
            s.pop();
        if(s.empty())
            r[i]=(n-i+1)*a[i];
        else
            r[i]=r[s.top()]+(s.top()-i)*a[i];
        s.push(i);
    }
    ll ans=0,idx=0;
    for(int i=1;i<=n;i++)
        if(l[i]+r[i]-a[i]>ans)
            ans=l[i]+r[i]-a[i],idx=i;
    for(int i=idx-1;i>=1;i--)
        a[i]=min(a[i],a[i+1]);
    for(int i=idx+1;i<=n;i++)
        a[i]=min(a[i-1],a[i]);
    for(int i=1;i<=n;i++)
        printf("%I64d ",a[i]);
    return 0;
}

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