题解 | #D-数列递推#

数列递推

https://ac.nowcoder.com/acm/contest/11173/D

D题

观察一下


对于 来说
其中
会发现 对于连续的
会有一些数的
对于连续的相同的 数来说,每多一个数对于 的余数相当与减去
即是一段数的和而这一段数每一个之间差值 为
本身不会超过 所以可以开一个 来记录前 项 每项之间差的前缀和
可以边求数边处理 时间复杂度

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int mod  = 998244353;
ll f[maxn], sum[600][maxn];
int K;
void solve(int pos) {
    // pos % a
    // = pos - k * a
    // k = pos / a;
    // 随着a的增加有一些数的k相同
    // 所以可以用整除分块优化 
    ll ans = 0;
    ans += f[0];
    for (int l = 2, r; l <= pos; l = r + 1) {
        r = pos / (pos / l);
        int k = pos / l;
        if (k > K) {
            ans = (ans + f[pos % l]);
            r = l;
            continue;
        }
        // 表示l~r 这一段的k 相同
        int ed = pos % l;
        int st = pos % r;
        if (st - k < 0) 
            ans = (ans + sum[k][ed]) % mod;
        else 
            ans = (ans + sum[k][ed] - sum[k][st - k]) % mod; 
    }
    f[pos] = ans;    
}

int main() {
    int n;
    cin >> n >> f[0];
    K = sqrt(n) + 1;
    int cnt = 0;
    for (int i = 1; i <= K; ++i) sum[i][0] = f[0];
    for (int i = 1; i <= n; ++i) {
        solve(i);
        cout << f[i] << ' ';
        for (int j = 1; j <= K; ++j) {
            if (i - j >= 0) sum[j][i] = (sum[j][i - j] + f[i]) % mod;
            else sum[j][i] = f[i];
        }
    }
    return 0;
}

补加:不是本身不会超过 , 是当超过 的部分直接暴力最多只有
所以可以对于在 的部分进行分块, 两个部分的时间总和不会超过 当时写题解没说清...sorry.

全部评论

相关推荐

美团 后端开发 总包n(15%是股票)
点赞 评论 收藏
分享
10-17 10:05
已编辑
北华大学 全栈开发
牛客872465272号:掉头发了哥
点赞 评论 收藏
分享
微风不断:兄弟,你把四旋翼都做出来了那个挺难的吧
点赞 评论 收藏
分享
5 收藏 评论
分享
牛客网
牛客企业服务