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.



京公网安备 11010502036488号