做法 1
首先第 \(i\) 次至少会加上数字 \(i\),所以前 \(i\) 次跳最少会到 \(\cfrac{i(i+1)}{2}\),所以跳的次数最大是根号级别的。
我们直接枚举操作到第几次,每次计算一个类似前缀和的数组来更新答案,每次都累加答案即可,类似于前缀和优化DP
.复杂度为 \(O(n\sqrt n)\)
#include<iostream> #include<cstring> using namespace std; typedef long long LL; const int maxn = 2e5 + 5, mod = 998244353; LL f[maxn], sum[maxn], ans[maxn]; int main(){ cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); int n, k; cin >> n >> k; f[0] = 1; for(int i = 1; ; i++){ int t = k + i - 1; for(int j = 0; j <= n; j++){ sum[j] = f[j]; if (j - t >= 0) sum[j] = (sum[j] + sum[j - t]) % mod; } for(int j = 0; j < t; j++) f[j] = 0; for(int j = t; j <= n; j++) f[j] = sum[j - t]; for(int j = t; j <= n; j++) ans[j] = (ans[j] + f[j]) % mod; if (1LL * i * (k + k + i - 1) > n * 2) break; } for(int i = 1; i <= n; i++) cout << ans[i] << " \n"[i == n]; }
做法 2
#include<bits/stdc++.h> #define h ((m+i)*(i-m+1)/2) using namespace std; const int mod=998244353; int n,m,ans[200005]; int dp[200005] = {1}; int main() { cin >> n >> m; for(int i=m; h<=n; i++) { for(int j=i; j<=n; j++) { dp[j]=(dp[j]+dp[j-i])%mod; } for(int j=h; j<=n; j++) { ans[j]=(ans[j]+dp[j-h])%mod; } } for(int i=1; i<=n; i++) { cout << ans[i] << " "; } return 0; }