数列递推
给定 f ( 0 ) f(0) f(0),定义 f n = ∑ i = 1 n f ( n m o d i ) f_n = \sum\limits_{i = 1} ^{n} f_{(n \mod i)} fn=i=1∑nf(nmodi),求 f 1 , f 2 , f 3 , … , f n − 1 , f n f_1, f_2, f_3, \dots, f_{n - 1}, f_{n} f1,f2,f3,…,fn−1,fn。
∑ i = 1 n f ( n m o d i ) ∑ i = 1 n f ( n − n i i ) \sum_{i = 1} ^{n} f_{(n \mod i)}\\ \sum_{i = 1} ^{n} f_{(n - \frac{n}{i} i)}\\ i=1∑nf(nmodi)i=1∑nf(n−ini)
显然 n i \frac{n}{i} in具有分块性质,当 n i \frac{n}{i} in大于 n \sqrt n n时, i i i只有 n \sqrt n n个选择,可以直接枚举,
否则 n i < n \frac{n}{i} < \sqrt n in<n时,可以考虑 S i , j = f i + f i − j + … S_{i, j} = f_i + f_{i - j} + \dots Si,j=fi+fi−j+…一个前缀和来转移。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, mod = 998244353;
int f[N], s[N][310], n;
inline int add(int x, int y) {
return x + y < mod ? x + y : x + y - mod;
}
inline int sub(int x, int y) {
return x >= y ? x - y : x - y + mod;
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
scanf("%d %d", &n, &f[0]);
for (int i = 1; i < 310; i++) {
s[0][i] = f[0];
}
for (int i = 1; i <= n; i++) {
for (int l = 1, r, k; l <= i; l = r + 1) {
r = i / (i / l), k = i / l;
if (k < 310) {
int L = i - k * r, R = i - k * l;
f[i] = add(f[i], s[R][k]);
if (L > k) {
f[i] = sub(f[i], s[L - k][k]);
}
}
else {
for (int j = l; j <= r; j++) {
f[i] = add(f[i], f[i - k * j]);
}
}
}
for (int j = 1; j < 310; j++) {
if (i >= j) {
s[i][j] = add(s[i - j][j], f[i]);
}
else {
s[i][j] = f[i];
}
}
}
for (int i = 1; i <= n; i++) {
printf("%d%c", f[i], i == n ? '\n' : ' ');
}
return 0;
}