cf edu 133 D

题意

img
img

思路

根据题意,最开始可以想到一个二维的dp状态
用dp[i][j]表示跳了j次刚好到i的方案数
如果是跳了j次,那么这次应该要被k+j-1整除才行
那么这样状态转移就是
dp[i][j] = dp[i][j]+dp[i-(k+j-1)x][j-1]
(k+j-1)x表示倍数
时间复杂度是nlogn
根号n,但是这样做不仅空间复杂度超限,并且时间也会超时
img
所以考虑如何去优化化此状态
我们发现每次跳j次都由j-1次转移而来,所以应该把第二维状态优化掉
这样dp[i]表示循环到j次时,能到i的方案数
考虑使用完全背包解决,但是这样做会出现一些问题,因为题目中要求每一次都必须要跳

for(int j = p; j <= n; j++){
            dp[j] += dp[j-p];
            dp[j] %= M;
    }

所以我们在刚开始要排除没有跳的情况
利用递推的方式,如果跳了j次的方案数都是正确转移的
那么第j+1次如果是被step整除
上一次从n~step 的方案数应该都和n-step~0等价(如果上一次正确转移,那么这一次直接跳step步不超过n就行)
而跳j+1次显然都是到不了0~step-1的(第j+1次必须跳step的整数倍),所以都置为0

代码

img
可复制版

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N = 2e5 + 5;
int dp[N];
int ans[N];
int n, k;
int pre;
const int M = 998244353;
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(int x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}
signed main()
{
    n = read();
    k = read();
    dp[0] = 1;
    for(int i = 1; i <= n; i++){
        //走了i步恰好能走到j的方案数
        int p = i + k - 1;
        pre += p;
        for(int j = n; j >= p; j--){
            dp[j] = dp[j-p];
        }
        for(int j = 0; j < p; j++){
            dp[j] = 0;
        }
        for(int j = p; j <= n; j++){
            dp[j] += dp[j-p];
            dp[j] %= M;
        }
        for(int j = 1; j <= n; j++){
            ans[j] += dp[j];
            ans[j] %= M;
        }
        if(pre > n) break;
    }
    for(int i = 1; i <= n; i++){
        cout << ans[i] << " ";
    }
    cout << endl;
    return 0;
}


posted @ 2022-08-06 10:30  Sun-Wind  阅读(28)  评论(1编辑  收藏  举报