D. Chip Move- Educational Codeforces Round 133
D. Chip Move
题意
给定一个n和k 对于一个1 - n的序列从0开始跳 第一步可以跳k的倍数 第二步可以跳k+1的倍数 以此类推
问跳到i的方案数(1 <= k <= n <= 2e5)
思路
如果当前跳第j步 第i个位置可以由第i - (k + j - 1)的位置跳过来 凡是能通过第j步跳到i - (k + j - 1)的 都能跳到i位置
我们可以知道 跳到n最多不会超过\(\sqrt(n)\)步 我们可以从小到大枚举步数 对于仅使用前x步的dp[i]可以由两部分组成
- 仅使用前x - 1步的跳到i - (x + j - 1)位置的方案数
- 仅使用前x步的跳到i - (x + j - 1)位置的方案数
对于没一步dp值都会改变 而前面位置的dp值改变会影响后面dp值的计算 所以我们开一个新的数组f记录加入当前一步 到位置i的方案数 然后再统一更新dp数组 进行下一轮转移
#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<array>
#include<unordered_map>
#include<ctime>
#include<random>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const ll inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const ll N = 2e5 + 5;
const ll M = 1e6;
const ll mod = 998244353;
ll n, k, ans[N], dp[N], f[N], sum;
void solve()
{
cin >> n >> k;
dp[0] = 1;//起始点初始化
sum = 0;
ll x;
for (int j = 1; j <= 700; j++) {
sum += k + j - 1;
x = k + j - 1;
//先全部重置为0
for (int i = 0; i <= n; i++)
f[i] = 0;
for (int i = sum; i <= n; i++) {//从第一个能
f[i] = (f[i] + dp[i - x]) % mod;//仅使用前j - 1步的方案数
f[i] = (f[i - x] + f[i]) % mod;//仅使用j步的方案数
}
for (int i = 0; i <= n; i++) {
ans[i] = (ans[i] + f[i]) % mod;//将仅使用j步到达的方案数加入答案
dp[i] = f[i];//更新当前dp值
//cout << j << ": " << i << " " << dp[i] << " " << ans[i] << "\n";
}
if (sum > n) break;
}
for (int i = 1; i <= n; i++)
cout << ans[i] << " \n"[i == n];
}
signed main() {
IOS;
int t = 1;
//cin >> t;
while (t--) {
solve();
}
}