2000dp

problem

  1. 观察发现可以有一个疑似nk的dp,意为第i步能走到j的方案数,\(dp[i][j] = \sum dp[i-1][j] (j==i-(s+k)\dot p)\)
  2. 这里时间和空间都会爆,但是观察发现k最多是根号n级别的那么复杂度就对了。
  3. 优化转移,一开始想的是前缀和优化,即第i步走到j的可能性求和,\(sum[i][j] = sum[i][j-(s+k)*2] +dp[i-1][j-(s+k)]\)
  4. 但是空间爆掉了。观察发现每一步的i之和前面有关,所以可以滚动优化,这样其实直接就做完了。
  5. 但是在第三步的位置,可以发现可转移的j等价于 \(j=i(mod (s+k))\)所以就可以通过模数求和来优化转移,这样简洁一些。
void solve() {
    int n, k;
    cin >> n >> k;
    vector<int> dp(n + 1, 0), ans(n + 1, 0);
    dp[0] = 1;
    for (int mn = 0; mn + k <= n; mn += k++) {
        vector<int> sum(k, 0);
        for (int i = mn; i <= n; i++) {
            int cur = dp[i];
            dp[i] = sum[i % k];
            sum[i % k] = add(sum[i % k], cur);
            ans[i] = add(ans[i], dp[i]);
        }
    }
    for (int i = 1; i <= n ;i++) cout << ans[i] << ' ';
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    // cin >> t;
    // prime();
    // for (int i = 1; i <= k; i++) {
    //     sum[i] = sum[i - 1] + pri[i];
    // }
    while(t--){
        solve();
    }
}

posted @ 2025-05-20 16:36  lyrrr  阅读(11)  评论(0)    收藏  举报