CodeForces547 B.Mike and Feet (單調棧/dp)

題意:

給定長度爲n的數組, n<=2e5
定義F(l,r)爲區間[l,r]的最小數,ans(k)爲max(F(l,l+k-1)),其中1<=l<=n-k,即ans(k)長度爲k的區間的F的最大值。
現在要求輸出k依次爲1到n的ans(k)值

思路:

用L(i)和R(i)記錄以第i個數爲最小值所能擴展的左右邊界,則可以用a(i)去嘗試更新ans(1)到ans(R(i)-L(i)+1),
因爲在區間[L(i),R(i)]內包含a(i)的區間最小值都爲a(i)。
先用每個a(i)更新ans(R(i)-L(i)+1),最後遞推一下就行了:ans(i)=max(ans(i),ans(i+1)),理由同上(大區間包含小區間)。

計算L(i),R(i)很容易想到單調棧,dp也能寫(見代碼)。

code(dp):

#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
int l[maxm],r[maxm];
int a[maxm];
int ans[maxm];
signed main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    a[0]=a[n+1]=-1;
    for(int i=1;i<=n;i++){
        int j=i-1;
        while(a[i]<=a[j])j=l[j];
        l[i]=j;
    }
    for(int i=n;i>=1;i--){
        int j=i+1;
        while(a[i]<=a[j])j=r[j];
        r[i]=j;
    }
    for(int i=1;i<=n;i++){
        l[i]++;
        r[i]--;
    }
    for(int i=1;i<=n;i++){
        int len=r[i]-l[i]+1;
        ans[len]=max(ans[len],a[i]);
    }
    for(int i=n-1;i>=1;i--){
        ans[i]=max(ans[i],ans[i+1]);
    }
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<' ';
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章