Wannafly 挑战赛 E 跳格子 计数DP

sum 个格子排成一排,每次可以往前跳 1-n 格,往回跳 1-m 格,而且在往回跳的时候只能跳在往前跳时踩过的格子。

现在,在格子上跳,问跳到最后一个格子上最后又跳回第一个格子之前的方案数 mod 233333333。
注意:只能一直向前跳,跳到最后一个格子,然后再往回跳,跳回第一个格子之前。

输入描述:

第一行一个数T,表示有T组数据
然后每组数据三个数 sum,n,m

输出描述:

对于每组数据输出一个数表示答案
示例1

输入

复制
2
5 2 4
5 2 3

输出

复制
52
42

备注:

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;
}


猜你喜欢

转载自blog.csdn.net/m0_38013346/article/details/80638594