题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4359
很明显dp,先预处理。
需要用到排列组合,然后可以用递推的方法求出来。
中间需要再加一个数组f来标记,不然会超时。
dp[i][k]表示i个数组成深度为k的树的总数
f[i][k]表示 i个数组成深度不超过k的树的总数
dp[i][k]=左子树深度为k-1&&右子树的深度小于等于k-1 + 左子树深度小于k-1&&右子树的深度等于k-1
View Code
1 # include<stdio.h> 2 # include<string.h> 3 # include<stdlib.h> 4 # define Mod 1000000007 5 __int64 dp[365][365],c[365][365],f[365][365]; 6 void solve() 7 { 8 int i,j; 9 for(i=1;i<=360;i++) 10 for(j=0;j<=i;j++) 11 { 12 if(j==0 || j==i) c[i][j]=1; 13 else c[i][j]=(c[i-1][j-1]+c[i-1][j])%Mod;//排序组合的递推求法,杨辉三角 14 } 15 } 16 int main() 17 { 18 int i,j,ncase,n,t,d,ans1; 19 int a[10]; 20 __int64 ans,count; 21 int k,h; 22 a[0]=1; 23 for(i=1;i<=9;i++) a[i]=a[i-1]*2; 24 solve(); 25 memset(dp,0,sizeof(dp)); 26 memset(f,0,sizeof(f)); 27 dp[0][0]=1; 28 f[0][0]=1; 29 dp[1][1]=1; 30 f[1][1]=1; 31 dp[2][2]=4; 32 f[2][2]=4; 33 for(i=3;i<=360;i++) 34 { 35 for(j=2;j<=9;j++) if(a[j]-1>=i) break; 36 for(k=j;k<=i;k++)//i个数深度为k时 37 { 38 //左子树的深度为k-1时,右子树的深度小于等于k-1 39 for(h=k-1;h<=i-2;h++)//左子树包含的节点数 40 { 41 ans=c[i-2][h]; 42 ans1=i-h-1; 43 ans1=ans1<k-1?ans1:k-1; 44 count=f[i-h-1][ans1]; 45 ans*=dp[h][k-1]; 46 ans%=Mod; 47 ans*=count; 48 ans%=Mod; 49 dp[i][k]+=ans; 50 dp[i][k]%=Mod; 51 } 52 dp[i][k]+=dp[i-1][k-1]; 53 dp[i][k]%=Mod; 54 55 //右子树的深度为k-1时,左子树的深度小于k-1 56 for(h=k-1;h<=i-1;h++) //右子树包含的节点数 57 { 58 ans=c[i-2][h-1]; 59 ans1=i-h-1; 60 ans1=ans1<k-2?ans1:k-2; 61 count=f[i-h-1][ans1]; 62 ans*=dp[h][k-1]; 63 ans%=Mod; 64 ans*=count; 65 ans%=Mod; 66 dp[i][k]+=ans; 67 dp[i][k]%=Mod; 68 } 69 dp[i][k]*=i; 70 dp[i][k]%=Mod; 71 f[i][k]=f[i][k-1]+dp[i][k]; 72 f[i][k]%=Mod; 73 } 74 75 } 76 scanf("%d",&ncase); 77 for(t=1;t<=ncase;t++) 78 { 79 scanf("%d%d",&n,&d); 80 printf("Case #%d: %I64d\n",t,dp[n][d]%Mod); 81 } 82 return 0; 83 }