题目大意:
高朗在一个神秘的宇宙中长大。他面对n个连续的二维平面。他向这些平面发射了一个k岁的衰变粒子。一个粒子可以直接穿过一个平面,但是,每个平面都会产生一个粒子的相同副本,以相反的方向运动,衰减年龄为k−1。如果一个粒子的衰变年龄等于1,它将不会产生副本。例如,如果有两个平面,一个粒子衰变年龄为3(向右),过程如下:(这里,D(x)指的是一个衰变年龄为x的单个粒子)
第一个平面向左生成一个D(2),并让D(3)继续向右;
第二个平面向左生成一个D(2),并让D(3)继续向右;
第一个平面让D(2)继续向左,并向右产生D(1);
第二个平面让D(1)继续向右移动(D(1)不能产生任何副本)。
总的来说,粒子的最终多集S为{D(3),D(2),D(2),D(1)}。(请参阅注释以获得该测试用例的可视化解释。)当飞机数量过多时,高朗无法应对这种复杂的情况。在给定n和k的情况下,帮助Gaurang找到多集S的大小。由于多集的大小可能非常大,所以必须对其取109+7的模输出。
注:粒子可以在两个平面之间来回运动而不相互碰撞。
emmm,这是一道状态转移的dp题。要注意状态的转移有方向,本轮向固定方向飞的例子继承的是上一轮向相反方向飞的粒子。
注:特殊的情况在于最开始的时候。我们假设粒子是往右飞的,那么他从左边第一个板反弹的情况要考虑上。(后续的反弹不会存在这种情况)。在加上最开始的第一个粒子,所以最后的答案要+2。
代码如下:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<map>
#include<math.h>
#include<string.h>
#include<queue>
#include<vector>
#include<set>
typedef long long ll;
using namespace std;
ll dp[1005][1005][3];
ll N=1e9+7;
int main() {
ios::sync_with_stdio(false);
cin.tie();
cout.tie();
ll t;
cin>>t;
while(t--){
memset(dp,0,sizeof dp);
ll n,m;
cin>>n>>m;
if(m==1){
cout<<1<<"\n";
continue;
}
for(int i=1;i<=n;i++){
dp[m][i][1]=1;
}
ll an=0;
for(int i=m-1;i>=1;i--){
dp[i][n][0]=dp[i+1][n-1][1];
for(int j=n;j>=1;j--){
dp[i][j][0]=(dp[i+1][j-1][1]+dp[i][j+1][0])%N;
}
an=(dp[i][1][0]+an)%N;
// cout<<"\n";
for(int j=1;j<=n;j++){
dp[i][j][1]=(dp[i+1][j+1][0]+dp[i][j-1][1])%N;
}
an=(an+dp[i][n][1])%N;
// cout<<"\n";
}
// for(int i=1;i<=n;i++){
// an=(an+(dp[1][i][0]+dp[1][i][1])%N)%N;
// }
an=(an+2)%N;
cout<<an<<"\n";
}
return 0;
}