题面
题解
考虑枚举序列最后一个位置的数字,得到 (f(x)) 的转移方程:
[f(x) = egin{cases}
1 & x = 1 \
sum_{d|x, d
eq x} f(d) & x > 1
end{cases}
]
设 (S(n) = sum_{i=1}^n f(i)),则
[S(n) = 1 + sum_{i=2}^n sum_{d|i,d
eq i} f(d)
]
两边同时加上 (S(n)) 得:
[egin{aligned}2 S(n) &= 1 + sum_{i=1}^n sum_{d|i} f(d) \&= 1 + sum_{d=1}^n sum_{i=1}^{leftlfloor frac {n}{d}
ight
floor} f(i) \&= 1 + sum_{d=1}^n Sleft(leftlfloor frac {n}{d}
ight
floor
ight)end{aligned}
]
于是有:
[S(n) = 1 + sum_{d=2}^n Sleft(leftlfloor frac {n}{d}
ight
floor
ight)
]
杜教筛即可。
代码
#include <cstdio>
const int M(5e6), N(M + 10), Mod(998244353);
int tot = 1, f[N], s[2500]; long long n;
inline int F(long long x) { return x <= M ? f[x] : s[n / x]; }
void Init()
{
int m = n < M ? n : M;
for (int i = f[1] = 1; i <= m; i++)
for (int j = i << 1; j <= m; j += i) f[j] = (f[j] + f[i]) % Mod;
for (int i = 1; i <= m; i++) f[i] = (f[i] + f[i - 1]) % Mod;
}
int main()
{
scanf("%lld", &n), Init(); while (n / tot > M) ++tot;
for (int t = tot; t; s[t] = (s[t] + 1) % Mod, t--)
for (long long i = 2, j, x = n / t; i <= x; i = j + 1)
j = x / (x / i), s[t] = (s[t] + (j - i + 1) * F(x / i)) % Mod;
printf("%d
", F(n));
return 0;
}