比赛的时候一直在敲这道题。一开题就盯住这个名字了。有人说他说是 treeDP 不一定真的是 treeDP。
总有时候别人会给你很诚恳的忠告。却只因自己陷得太深无法自拔。关键是自己不想出去。
跑题了。
读错题了。n,d. d 是说 深度恰好为 d , 我给理解为不超过 d 。 于是最后答案变成 ans(n,d) - ans(n, d-1) 就可以了。
C(n, m) 那个东西 , 由于里面有除法 , 不能直接 mod 。这里套了一个我完全不懂的模版 。
依然不能 AC 。后来输出到一个文件里, 发现里面有负数 。 发现有个三连乘 , 可能超 __int64 . 太贱了。
一道题,核心东西就那么一点,乱七八糟的一大堆。短木板原则么。
其实这道题我也不知道更像DP 还是组合数学 还是都不是 。
很多事 , 本来就不用分那么清楚。也分不清楚。
const int N = 370;
const __int64 mod = 1000000007;
__int64 dp[N][N], CC[N][N];
inline __int64 log2(__int64 n)
{
__int64 a = 0;
while(n)
{
a++;
n>>=1;
}
return a;
}
__int64 Extend_euclid(__int64 a,__int64 b,__int64 &x,__int64 &y)
{
__int64 d=0,t=0;
if(b==0)
{
x=1;
y=0;
return a;
}
else
{
d=Extend_euclid(b,a%b,x,y);
t=x;
x=y;
y=t-a/b*y;
}
return d;
}
__int64 Bignum_Div(__int64 a,__int64 b,__int64 mod)
{
__int64 x=0,y=0;
Extend_euclid(b,mod,x,y);//扩展gcd求出(2*n)*x-mod*k=1的x
__int64 ans= a*x%mod;//ans/(2*n)%p = ((ans*x)/(2*n*x))%p=ans*x%mod; (p=1000000007,显然gcd(2*n,p)=1)
while(ans<0)
ans+=mod;
return ans;
}
int64 ice(int64 x,int64 y,int64 mod)
{
int64 temp=x,res=1;
while(y)
{
if(y&1)
res=(res*temp)%mod;
temp=(temp*temp)%mod;
y>>=1;
}
return res;
}
int64 cnm(int64 x,int64 y,int64 mod)
{
int64 ans=1,a,b;
for(int64 i=0;i<y;i++)
{
a=(x-i)%mod;
b=(y-i)%mod;
ans=ans*(a*ice(b,mod-2,mod)%mod)%mod;
}
return ans%mod;
}
__int64 lucas(__int64 x,__int64 y,__int64 mod)
{
if(y==0)
return 1;
return (cnm(x%mod,y%mod,mod)*lucas(x/mod,y/mod,mod))%mod;
}
__int64 C(int n, int m)
{
if(n==0 || m==0 || m>=n) return 1;
if(CC[n][m]!=-1) return CC[n][m];
__int64 ans = 1;
int nn=n, mm=m;
m = min( m, n-m );
for(int i=1; i<=m; i++, n--)
{
ans=Bignum_Div( ans*(__int64)n%mod, (__int64)i, mod )%mod;
//ans = ans*(__int64)n/(__int64)i%mod;
}
return CC[nn][mm] = ans;
}
__int64 dfs(int64 n, int64 d)
{
d = min(n, d);
if(dp[n][d]!=-1) return dp[n][d]; //记忆化
int k = log2(n); //至少层数
if(d<k) return dp[n][d] = 0; //你懂得
if(n==1) return dp[n][d] = 1;
if(n==0) return dp[n][d] = 1;
int i, j;
__int64 tmp = 0;
for(i=0; i<n; i++)
{
__int64 tmp1 = dfs(n-i-1, d-1); //分给右孩子n-i-1个点
if(tmp1==0) continue;
__int64 tmp0 = dfs(i, d-1); //分给左孩子i个点
if(tmp0==0) break;
tmp =tmp+ C(n-2, i)*tmp0%mod*tmp1%mod; //分给左孩子的不是根节点,不是除根节点最大的点,所以有C(n-2, i)
tmp %= mod;
}
return dp[n][d] = tmp*(__int64)n%mod; //根节点有n种
}
int main()
{
int t, tt=0, n, d;
memset(dp, -1, sizeof(dp));
memset(CC, -1, sizeof(CC));
__int64 ii, j;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&d);
printf("Case #%d: %I64d\n", ++tt, (dfs(n, d)-dfs(n,d-1)+mod)%mod);
}
return 0;
}