https://codeforces.com/contest/1498/problem/C
题目大意:一个粒子年龄为k,一开始往右,每穿过一个板子年龄就会减1,且会产生一个向反方向的年龄为k-1的粒子(如果当前粒子年龄为1,则不会产生反方向的粒子)。
给定n和k,n是由n个板子,k是初始粒子年龄。
求出最后总共会有多少个粒子。
样例:n=2,k=3;
记忆化搜索和dp都行
dp:
集合:f[i,j]代表一个年龄为i要穿过j个板子的粒子,生成的所有粒子
属性:sum
状态转移方程:
dp:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll mod=1000000007;
const int N=1010;
const int inf=0x3f3f3f3f;
const double eps=1e-6;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
int t,n,m,k;
ll f[N][N];
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
memset(f,0,sizeof f);
for(int i=1;i<=n;i++) f[1][i] = 1;
for(int i=1;i<=k;i++) f[i][0] = 1;
for(int i=1;i<=k;i++){
for(int j=1;j<=n;j++){
f[i][j] = (f[i][j-1] + f[i-1][n - j]) % mod;
}
}
printf("%lld\n", f[k][n]);
}
return 0;
}
记忆化搜索:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll mod=1000000007;
const int N=1010;
const int inf=0x3f3f3f3f;
const double eps=1e-6;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
ll t,n,m,k;
ll f[N][N];
ll dfs(ll x,ll y){
if(x < 1) return f[x][y] = 1;
if(y == 1) return f[x][y] = 1;
if(f[x][y] != -1) return f[x][y];
ll res = 0;
res = (res + dfs(n-x,y-1)) % mod;//产生的往反方向的新粒子
res = (res + dfs(x-1,y)) % mod;//原来的粒子
return f[x][y] = res;
}
int main(){
scanf("%lld",&t);
while(t--){
memset(f,-1,sizeof f);
scanf("%lld%lld",&n,&k);
dfs(n,k);
printf("%lld\n",f[n][k]);
}
return 0;
}