【BZOJ3769】BST again [DP]
BST again
Time Limit: 10 Sec Memory Limit: 256 MB[Submit][Status][Discuss]
Description
求有多少棵大小为n的深度为h的二叉树。(树根深度为0;左右子树有别;答案对1000000007取模)
Input
第一行一个整数T,表示数据组数。
以下T行,每行2个整数n和h。
Output
共T行,每行一个整数表示答案(对1000000007取模)
Sample Input
2
2 1
3 2
2 1
3 2
Sample Output
2
4
4
HINT
1<=n<=600,0<=h<=600,1<=T<=10
Solution
我们运用DP来求解。
记f[i][j]表示点数为i,深度==j的方案数;
记g[i][j]表示点数为i,深度<=j的方案数。
转移的时候所以枚举一个点k作为根,那么左边显然就有k-1个点,右边就有i-k个点。
此时深度恰好为j-1的方案数为:
g[k-1][j-1] * g[i-k][j-1] - g[k-1][j-2] * g[i-k][j-2]。
所以我们就可以得到答案了。
Code
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cmath> 8 using namespace std; 9 typedef long long s64; 10 11 const int ONE = 1005; 12 const int MOD = 1e9 + 7; 13 14 int T; 15 int n, h; 16 int x, y; 17 int f[ONE][ONE], g[ONE][ONE]; 18 19 struct pwoer 20 { 21 int x, y; 22 }a[ONE]; 23 24 int get() 25 { 26 int res=1,Q=1; char c; 27 while( (c=getchar())<48 || c>57) 28 if(c=='-')Q=-1; 29 if(Q) res=c-48; 30 while((c=getchar())>=48 && c<=57) 31 res=res*10+c-48; 32 return res*Q; 33 } 34 35 void Modit(int &a) 36 { 37 if(a < 0) a += MOD; 38 if(a >= MOD) a -= MOD; 39 } 40 41 int main() 42 { 43 T = get(); 44 for(int i = 1; i <= T; i++) 45 a[i].x = get(), a[i].y = get() + 1, 46 n = max(n, a[i].x), h = max(h, a[i].y); 47 48 f[0][0] = 1; for(int i = 0; i <= h; i++) g[0][i] = 1; 49 f[1][1] = 1; for(int i = 1; i <= h; i++) g[1][i] = 1; 50 for(int i = 2; i <= n; i++) 51 { 52 for(int j = 2; j <= i; j++) 53 for(int k = 1; k <= i; k++) 54 Modit(f[i][j] += (s64)g[k - 1][j - 1] * g[i - k][j - 1] % MOD - (s64)g[k - 1][j - 2] * g[i - k][j - 2] % MOD); 55 56 g[i][0] = f[i][0]; 57 for(int j = 1; j <= h; j++) 58 Modit(g[i][j] = g[i][j - 1] + f[i][j]); 59 } m 60 61 for(int i = 1; i <= T; i++) 62 printf("%d\n", f[a[i].x][a[i].y]); 63 64 }