洛谷传送门
SPOJ传送门
题意翻译
• 在一个 n 维无限空间中,一开始原点处有一个细胞。
• 细胞每秒都会增殖,每个原有细胞在增值后都会消亡,在与它曼哈顿距离恰为 1 的所有位置都会新增一个细胞。
• 求 T 秒后,原点处会有多少细胞,答案 %(1e9+7)。
• Q 组询问。Q≤20000 n≤100 T≤200。
输入输出格式
输入格式
第一行一个正整数 Q Q Q。
以下 Q Q Q行, 每行两个正整数 n , T n,T n,T, 表示一组询问。
输出格式
Q Q Q行, 每行分别代表该组询问的答案。
输入输出样例
输入样例:
3
1 2
2 3
3 2
输出样例
2
0
6
解题分析
不难发现, 题目就是让我们求 n n n维空间中一条能够回到原点、长度为 T T T的路径。
考虑分开每一维考虑, 设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示当前考虑(并不是已经使用)了 i i i个维度, 走了 j ∗ 2 j*2 j∗2步后回到原点的方案数, 这样就对 d p [ i + 1 ] [ j + k ] dp[i+1][j+k] dp[i+1][j+k]有 ( 2 ∗ ( j + k ) 2 ∗ k ) ( 2 ∗ k k ) ∗ d p [ i ] [ j ] \binom{2*(j+k)}{2*k}\binom{2*k}{k}*dp[i][j] (2∗k2∗(j+k))(k2∗k)∗dp[i][j]的贡献。
怎么理解这个呢? 其实就是从总步数中选出了 2 ∗ k 2*k 2∗k步分配到其他的一个维度上, 然后从 2 ∗ k 2*k 2∗k步中选出 k k k步向正方向走, 这样当 k = 0 k=0 k=0的时候就等于并不使用这个维度, 这样就没有考虑漏情况。
总复杂度 O ( N 3 + Q ) O(N^3+Q) O(N3+Q)。
代码如下:
#include <cstdio>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 505
#define ll long long
#define MOD 1000000007
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
ll C[MX][MX], dp[MX][MX];
void pre()
{
for (R int i = 0; i <= 200; ++i) C[i][0] = 1;
for (R int i = 1; i <= 200; ++i)
for (R int j = 1; j <= i; ++j)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
dp[0][0] = 1;
for (R int i = 0; i < 100; ++i)
for (R int j = 0; j <= 100; ++j)
{
for (R int k = 0; j + k <= 100; ++k)
(dp[i + 1][j + k] += C[2 * (k + j)][2 * k] * C[2 * k][k] % MOD * dp[i][j] % MOD) %= MOD;
}
}
int main(void)
{
int q, n, t;
in(q); pre();
W (q--)
{
in(n), in(t);
if (t & 1) {puts("0"); continue;}
else printf("%lld\n", dp[n][t >> 1]);
}
}