题意:有一行连续排列的墙,你射出去一个大小为k的粒子,它可以穿透一面墙。设穿透一面墙时的粒子大小为tmp,那么每穿过一面墙,都会分裂出一个大小为$tmp - 1$的粒子,该粒子也有上述性质。当粒子大小为1的时候就不分裂,只穿透了。问最后所有粒子都不分裂的时候,一共分裂出了多少粒子(包括最开始的粒子)
方法:DP
状态表达:$dp[i][j][k]$表示经过第i面墙上的类型为j的粒子,其中为穿透这面墙(k = 0)或者在这面墙分裂(k = 1)的数量。
状态转移:
这个比较复杂,我们通过模拟注意到奇偶性相同的粒子都是只会朝一个方向走的,所以我们有以下这些
与最开始的粒子奇偶性相同时:
$dp[i][j][0] = dp[i - 1][j][0] + dp[i - 1][j][1]$
$dp[i][j][1] = dp[i + 1][j + 1][0] + dp[i + 1][j + 1][1]$
与最开始的粒子奇偶性不相同时:
$dp[i][j][0] = dp[i + 1][j][0] + dp[i + 1][j][1]$
$dp[i][j][1] = dp[i - 1][j + 1][0] + dp[i - 1][j + 1][1]$
我们注意到,状态转移的第一维有从上一个转移的,也有从下一个转移的,说明我们要分多次转移。
最后别忘了取模
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL,LL> PLL;
const int INF = 0x3f3f3f3f, N = 1010, MOD = 1e9 + 7;
inline int lc(int u) {return u << 1;}
inline int rc(int u) {return u << 1 | 1;}
inline int lowbit(int x) {return x & (-x);}
LL dp[N][N][2];
inline void solve() {
int n, k;
cin >> n >> k;
int c = k % 2;
memset(dp, 0, sizeof dp);
for (int i = 0; i <= n + 1; i ++ ) dp[i][k][0] = 1;
for (int j = k - 1; j; j -- ) {
for (int i = 1; i <= n; i ++ ) {
if (j % 2 == c) dp[i][j][0] = (dp[i - 1][j][0] + dp[i - 1][j][1]) % MOD;
else dp[i][j][1] = (dp[i - 1][j + 1][0] + dp[i - 1][j + 1][1]) % MOD;
}
for (int i = n; i; i -- ) {
if (j % 2 == c) dp[i][j][1] = (dp[i + 1][j + 1][0] + dp[i + 1][j + 1][1]) % MOD;
else dp[i][j][0] = (dp[i + 1][j][0] + dp[i + 1][j][1]) % MOD;
}
for (int i = 1; i <= n; i ++ ) {
if (j % 2 == c) dp[i][j][0] = (dp[i - 1][j][0] + dp[i - 1][j][1]) % MOD;
else dp[i][j][1] = (dp[i - 1][j + 1][0] + dp[i - 1][j + 1][1]) % MOD;
}
}
LL res = 1;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= k; j ++ ) res = (res + dp[i][j][1]) % MOD;
cout << res << endl;
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t; cin >> t;
while (t -- )
solve();
return 0;
}