【BZOJ 3769】【spoj 8549】BST again
问题描述
求有多少棵大小为n的深度为h的二叉树。(树根深度为0;左右子树有别;答案对1000000007取模)
输入格式
第一行一个整数T,表示数据组数。 以下T行,每行2个整数n和h。
输出格式
共T行,每行一个整数表示答案(对1000000007取模)
样例输入
2
2 1
3 2
样例输出
2
4
数据范围
对于100%的数据,1≤n≤600,0≤h≤600,1≤T≤10
题解
f[i][j]表示大小为i,深度不超过j的树的个数
除去根节点,子树中还有i-1个节点,枚举左右子树的节点数,乘法原理相乘
f[i][j]=∑f[i-k-1][j-1]+f[k][j-1] (0≤k<i)
边界条件,当i==0时,由于乘法的需要,f[0][j]=1;当j==0时,当且仅当i==1时存在一个二叉树,f[i][0]=(i==1)
如果用记忆化搜索,i==0的条件必须写在j==0前面,因为j==0的条件后还有i==1的条件,不满足这个条件,还有i≠0的条件,包含了i==0的条件(有点绕?)
1 #include <cstdio> 2 const int maxn=1000000007; 3 int T,n,h,f[605][605],ans; 4 int dp(int i,int j) 5 { 6 if (i==0) return 1; 7 if (j==0) return i==1; 8 if (f[i][j]) return f[i][j]; 9 for (int k=0;k<i;k++) 10 f[i][j]=(f[i][j]+1ll*dp(i-k-1,j-1)*dp(k,j-1)%maxn)%maxn; 11 return f[i][j]; 12 } 13 int main() 14 { 15 int i,j,k; 16 scanf("%d",&T); 17 while (T--) 18 { 19 scanf("%d%d",&n,&h); 20 ans=dp(n,h)-dp(n,h-1); 21 while (ans<0) ans+=maxn; 22 printf("%d\n",ans); 23 } 24 return 0; 25 }