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]可以由两部分组成

  1. 仅使用前x - 1步的跳到i - (x + j - 1)位置的方案数
  2. 仅使用前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();
	}
}
posted @ 2022-08-13 21:30  Yaqu  阅读(61)  评论(0)    收藏  举报