1. 程式人生 > >[BZOJ4824][CQOI2017]老C的鍵盤(樹形DP)

[BZOJ4824][CQOI2017]老C的鍵盤(樹形DP)

程序員 string 多少 clu data stat 決定 html www.

4824: [Cqoi2017]老C的鍵盤

Time Limit: 10 Sec Memory Limit: 512 MB
Submit: 193 Solved: 149
[Submit][Status][Discuss]

Description

老 C 是個程序員。 作為一個優秀的程序員,老 C 擁有一個別具一格的鍵盤,據說這樣可以大幅提升寫程序的速度,還能讓寫出來的程序 在某種神奇力量的驅使之下跑得非常快。小 Q 也是一個程序員。有一天他悄悄潛入了老 C 的家中,想要看看這個 鍵盤究竟有何妙處。他發現,這個鍵盤共有n個按鍵,這n個按鍵雖然整齊的排成一列,但是每個鍵的高度卻互不相同 。聰明的小 Q 馬上將每個鍵的高度用 1 ~ n 的整數表示了出來,得到一個 1 ~ n 的排列 h1, h2,..., hn 。為了 回去之後可以仿造一個新鍵盤(新鍵盤每個鍵的高度也是一個 1 ~ n 的排列),又不要和老 C 的鍵盤完全一樣,小 Q 決定記錄下若幹對按鍵的高度關系。作為一個程序員,小 Q 當然不會隨便選幾對就記下來,而是選了非常有規律的 一些按鍵對:對於 i =2,3, ... , n,小 Q 都記錄下了一個字符<或者>,表示 h_[i/2] < h_i 或者h _[i/2] > h_i 。於是,小 Q 得到了一個長度為n ? 1的字符串,開開心心的回家了。現在,小 Q 想知道滿足他所記錄的高度關系的 鍵盤有多少個。雖然小 Q 不希望自己的鍵盤和老 C 的完全相同,但是完全相同也算一個滿足要求的鍵盤。答案可 能很大,你只需要告訴小 Q 答案 mod 1,000,000,007 之後的結果即可。

Input

輸入共 1 行,包含一個正整數 n 和一個長度為 n ? 1 的只包含<和>的字符串,分別表示鍵 盤上按鍵的數量,和小 Q 記錄的信息,整數和字符串之間有一個空格間隔。

Output

輸出共 1 行,包含一個整數,表示答案 mod 1,000,000,007後的結果。

Sample Input

5 <>><

Sample Output

3
共5個按鍵,第1個按鍵比第2個按鍵矮,第1個按鍵比第3個按鍵高,第2個按鍵比第4個
按鍵高,第2個按鍵比第5個按鍵矮。
這5個按鍵的高度排列可以是 2,4,1,3,5 , 3,4,1,2,5 , 3,4,2,1,5 。

HINT

Source

[Submit][Status][Discuss]

[BZOJ3167][P4099][HEOI2013]SAO(樹形DP)

完全二叉樹反而好做些,且數據開到了$O(n^4)$都能過的範圍,直接套上一題的式子即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 using namespace std;
 6 
 7 const
int N=210,mod=1000000007; 8 char s[N]; 9 int n,a[N],sum[N][N],sz[N],f[N][N],g[N],C[N][N]; 10 11 void dfs(int x){ 12 f[x][1]=sum[x][1]=sz[x]=1; 13 for (int s=x<<1; s<=((x<<1)|1); s++){ 14 if (s>n) return; dfs(s); 15 memset(g,0,sizeof(g)); 16 if (a[s]==2){ 17 rep(i,1,sz[x]) if (f[x][i]) rep(j,0,sz[s]) if (sum[s][j]) 18 g[i+j]=(g[i+j]+1ll*f[x][i]*sum[s][j]%mod*C[i+j-1][i-1]%mod*C[sz[x]-i+sz[s]-j][sz[x]-i]%mod)%mod; 19 }else{ 20 rep(i,1,sz[x]) if (f[x][i]) rep(j,0,sz[s]) 21 g[i+j]=(g[i+j]+1ll*f[x][i]*(sum[s][sz[s]]-sum[s][j]+mod)%mod*C[i+j-1][i-1]%mod*C[sz[x]-i+sz[s]-j][sz[x]-i])%mod; 22 } 23 sz[x]+=sz[s]; 24 rep(i,1,sz[x]) f[x][i]=g[i],sum[x][i]=(sum[x][i-1]+g[i])%mod; 25 } 26 } 27 28 int main(){ 29 freopen("keyboard.in","r",stdin); 30 freopen("keyboard.out","w",stdout); 31 scanf("%d",&n); scanf("%s",s+1); 32 rep(i,0,n) C[i][0]=1; 33 rep(i,1,n) rep(j,1,n) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; 34 rep(i,2,n) if (s[i-1]==<) a[i]=1; else a[i]=2; 35 dfs(1); printf("%d\n",sum[1][sz[1]]); 36 return 0; 37 }

[BZOJ4824][CQOI2017]老C的鍵盤(樹形DP)