sum 个格子排成一排,每次可以往前跳 1-n 格,往回跳 1-m 格,而且在往回跳的时候只能跳在往前跳时踩过的格子。
现在,在格子上跳,问跳到最后一个格子上最后又跳回第一个格子之前的方案数 mod 233333333。
注意:只能一直向前跳,跳到最后一个格子,然后再往回跳,跳回第一个格子之前。
输入描述:
第一行一个数T,表示有T组数据 然后每组数据三个数 sum,n,m
输出描述:
对于每组数据输出一个数表示答案
备注:
T<=5,sum<=4e5,n<=10,m<=10
题解:
从楼梯的最上面跳回最下面可以看作是向上跳
所以题意就变成了
跳两次
第二次跳必须踩在第一次跳的台阶上
则第二次跳的台阶的集合必定是作为第一次跳的台阶的子集
我们考虑枚举枚举第二次跳的距离i
搜索有第一次跳的长度为i的方案数vi
然后有递推式f[i]=f[i-1]*v1+f[i-2]*v2+..+f[i-m]*vm
O(n*m)递推即可
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+10;
const int mod = 233333333;
ll val[15],dp[maxn];
int sum,n,m;
int main()
{
int caset;scanf("%d",&caset);
while(caset--)
{
scanf("%d%d%d",&sum,&n,&m);
memset(val,0,sizeof(val));
memset(dp,0,sizeof(dp));
val[0] = 1;
/// 预处理出第一遍走步长为i的方案数
for(int i=1;i<=m;i++) {
for(int j=1;j<=i&&j<=n;j++) {
val[i] = (val[i] + val[i-j]) % mod;
}
}
dp[0] = 1;
for(int i=1;i<=sum;i++) {
/// 相当于往前后j步的时候还需要考虑下向前跳j步的种类数(组合一下)
for(int j=1;j<=i&&j<=m;j++) {
dp[i] = (dp[i] + dp[i-j]*val[j]%mod) % mod;
}
}
printf("%lld\n",dp[sum]);
}
return 0;
}