题意
Solution
由于最后求的是原点的细胞数,那么一定是先从原点向外扩展,再扩展回来到达原点。那么我们就可以把答案转化为从原点出发,经过 T T T时间回到原点的方案数。
于是我们考虑
d
p
dp
dp,设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示用
i
i
i个维度,经过
2
j
2j
2j的时间回到原点的方案数(显然奇数时间答案为0)。那么我们考虑对于一个新的维度
i
+
1
i+1
i+1和新的时间
2
(
j
+
k
)
2(j+k)
2(j+k),我们可以从所有时间中,用
2
k
2k
2k时间去第
i
+
1
i+1
i+1个维度,于是得到方案
C
2
(
j
+
k
)
2
k
C_{2(j+k)}^{2k}
C2(j+k)2k,同时这
2
k
2k
2k时间中,我们又需要分配
k
k
k的时间向外扩展,剩余
k
k
k的时间向内扩展,于是又有方案数
C
2
k
k
C_{2k}^{k}
C2kk,所以可以得出转移方程:
f
[
i
+
1
]
[
j
+
k
]
=
f
[
i
]
[
j
]
∗
C
2
(
j
+
k
)
2
k
∗
C
2
k
k
f[i+1][j+k]=f[i][j]*C_{2(j+k)}^{2k}*C_{2k}^{k}
f[i+1][j+k]=f[i][j]∗C2(j+k)2k∗C2kk
于是进行一遍预处理,复杂度
O
(
n
3
)
O(n^3)
O(n3),然后
O
(
1
)
O(1)
O(1)处理每个询问。总复杂度
O
(
n
3
+
Q
)
O(n^{3}+Q)
O(n3+Q)。
Code
#include <bits/stdc++.h>
#define ll long long
#define P ((ll)1e9+7)
#define MAX 205
using namespace std;
ll C[MAX][MAX], f[MAX][MAX];
void init(){
C[0][0] = C[1][1] = 1;
for(int i = 1; i <= 200; i++){
C[i][0] = 1;
for(int j = 1; j <= i; j++){
C[i][j] = (C[i-1][j-1]+C[i-1][j])%P;
}
}
}
int main()
{
init();
f[0][0] = 1;
for(int i = 0; i <= 100; i++){
for(int j = 0; j <= 100; j++){
for(int k = 0; k+j <= 100; k++){
f[i+1][j+k] += f[i][j]*C[2*(j+k)][2*k]%P*C[2*k][k]%P;
f[i+1][j+k] %= P;
}
}
}
int t, n, T;
cin >> t;
while(t--){
scanf("%d%d", &n, &T);
if(T&1) puts("0");
else
printf("%lld\n", f[n][T/2]);
}
return 0;
}