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
对于100%的数据,1<=n<=600,0<=h<=600,1<=T<=10
前几天刚做过的题目,就被BZOJ吞掉了。万恶的资本家。。
做法:动态规划
设状态a[i][j]为大小为i高度为j的二叉树个数,则
a[i][j]=∑a[k][j-1]*(∑a[i-k-1][e])*2+∑a[q][j-1]*a[w][j-1],
意思就是将情况分割成二叉树左子树高度为j-1且右子树高度不足j-1、左子树不足j-1且右子树为j-1、左子树右子树皆为j-1,
然后注意边界,而且∑a[i-k-1][e]可以边做边处理用b[i-k-1][e]保存a[i-k-1][0~e]的和,就不用再去求了。
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; #define N 605 #define M 1000000007 long long a[N][N],b[N][N]; int n,m,d[N],c[N],f[12][2],Na=-1,Mi=-1,T; int Minn(int x,int y) { if (x<y) return x;else return y; } int main() { int i,j,T,k,l,q,w,e,ts; memset(a,0,sizeof(a));memset(b,0,sizeof(b)); memset(c,0,sizeof(c));memset(d,0,sizeof(d)); scanf("%d",&T); for (i=1;i<=T;i++) { scanf("%d%d",&f[i][0],&f[i][1]); if (f[i][0]>Na) Na=f[i][0]; if (f[i][1]>Mi) Mi=f[i][1]; } c[2]=1;c[4]=1;c[8]=1;c[16]=1;c[32]=1;c[64]=1;c[128]=1; c[256]=1;c[512]=1; a[1][1]=1;b[1][1]=1;a[0][0]=1;b[0][0]=1;b[0][1]=1; for (i=2;i<=Na;i++) { b[0][i]=1; b[1][i]=1; if (i>9) d[i]=N; } d[0]=1;d[1]=2;d[2]=4;d[3]=8;d[4]=16;d[5]=32;d[6]=64;d[7]=128; d[8]=256;d[9]=512;q=1;Mi++; for (i=2;i<=Na;i++) { if (c[i]) q++; for (j=q;j<=Minn(Mi,i);j++) { for (k=j-1;k<=Minn(i-1,d[j-1]-1);k++) a[i][j]=(a[i][j]+a[k][j-1]*b[i-k-1][j-2]*2 +a[k][j-1]*a[i-k-1][j-1])%M; b[i][j]=(b[i][j-1]+a[i][j])%M; } for (j=i+1;j<=Mi;j++) b[i][j]=b[i][j-1]; } for (i=1;i<=T;i++) printf("%lld ",a[f[i][0]][f[i][1]+1]); return 0; }