[BZOJ1996]chorus 合唱隊

題目描述

這裏寫圖片描述

輸入格式

這裏寫圖片描述

輸出格式

這裏寫圖片描述

樣例輸入

4
1701 1702 1703 1704

樣例輸出

8

提示

這裏寫圖片描述

題解

 發現題目要求的是方案數,那麼我們想到了區間DP。
 由於題目給定的加入元素的方式,我們可以清楚的知道新元素要麼加在隊頭要麼加在隊尾,所以說在某種程度上這個序列是連續的(或者說有特殊的性質),並且對於新加入的元素的位置的影響只跟上一次的加入元素有關。
 根據這個特殊性質我們想到了區間DP,令f[l][r][0or1] 表示區間l~r中現在加入的元素放在隊頭\隊尾。
 那麼顯然,初值即爲f[i][i][0]=1f[i][i][1]=1 ,並且如果放在隊頭的話f[l][r][0] 應該從f[l+1][r][0or1] 推導過來,繼續思考發現從f[l+1][r][0] 推導過來的條件是a[l]<a[l+1] ,從f[l][r][1] 推導過來的條件則應該是a[l]<a[r]f[l][r][1] 情況類似。
 這樣跑一遍區間DP最後答案顯然就是f[1][n][0]+f[1][n][1] 了。
 轉移方程:
 f[i][j][0/1] 表示取到數列中從i到j的區間,上一個取到的是數列左邊/右邊的數
 f[i][j][0]=f[i+1][j][0](a[i]<a[i+1])+f[i+1][j][1](a[i]<a[j])
 f[i][j][1]=f[i][j+1][0]+(a[j]>a[i])+f[i][j+1][1](a[j]>a[j1])

代碼

#include <cstdio>
#include <cstring>
#include <algorithm>

#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
const int size = 1000+10;
const int mod = 19650827;

int a[size],f[size][size][2];
int n;

inline int read(int &in) {
    in=0;int f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) in=in*10+ch-'0';
    return in*f;
}

int main() {
    read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=n;i++) f[i][i][1]=1;

    for(int i=n;i>=1;i--)
        for(int j=i+1;j<=n;j++) {
            if (a[i]<a[i+1])f[i][j][0]+=f[i+1][j][0];
            if (a[i]<a[j])f[i][j][0]+=f[i+1][j][1];
            if (a[j]>a[i])f[i][j][1]+=f[i][j-1][0];
            if (a[j]>a[j-1])f[i][j][1]+=f[i][j-1][1];
            f[i][j][0]%=mod; f[i][j][1]%=mod;
        }

    printf("%d\n",(f[1][n][0]+f[1][n][1])%mod);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章