Description

求有多少棵大小为n的深度为h的二叉树。(树根深度为0;左右子树有别;答案对1000000007取模)

Input

第一行一个整数T,表示数据组数。
以下T行,每行2个整数n和h。

Output

共T行,每行一个整数表示答案(对1000000007取模)

Sample Input

2
2 1
3 2

Sample Output

2
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\n",a[f[i][0]][f[i][1]+1]);
    return 0;
 }