C. Planar Reflections
题面:
中文题意:
大概是说,给定一个可以穿越墙体的粒子(寿命为 k),每穿越一次墙体会产生一个反向寿命为 k−1 的粒子。(如果粒子寿命为1则不再产生反向粒子),问最后有多少粒子飞出。
就像这样。
思路:
老dp人了。
dp[i][j] = (dp[i - 1][j] + dp[n - i][j - 1])
- 设
dp[i][j]
为某个粒子前面还有i个平面,当前的衰变年龄为j。 - 每当向前移动一个平面,会产生一个衰变年龄减1(j-1)且方向相反(i=n-i)的粒子;
- 还会产生一个平面减1(i-=1),衰变年龄不变(j=j)的粒子。
- 易得
dp[i][1] = 1
(i=1~n),因为衰变年龄为1时不分裂。 - 同样的易得
dp[0][j] = 1
(j=1~k),因为不经过平面也不分裂。 - 最终要求
dp[n][k]
。
代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
int dp[2000][2000];
int main() {
int T;
cin >> T;
while (T--) {
int n, k;
cin >> n >> k;
for (int i = 0; i <= n; i++)
for (int j = 0; j <= k; j++)
dp[i][j] = 0;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
dp[i][1] = 1;
for (int j = 1; j <= k; j++)
dp[0][j] = 1;
for (int j = 1; j <= k; j++)
for (int i = 1; i <= n; i++)
//引用关系,需要先枚举j再枚举i进行处理。
//从当前衰变年龄为最终态1开始从后往前倒推。
//如果从还剩下一个平面开始倒推,就会产生错误。
dp[i][j] = (dp[i - 1][j] + dp[n - i][j - 1]) % mod;
cout << dp[n][k] << endl;
}
}