LOJ#6714. Stupid Product
题面
题解
考虑枚举序列最后一个位置的数字,得到 \(f(x)\) 的转移方程:
\[f(x) = \begin{cases}
1 & x = 1 \\
\sum_{d|x, d \neq 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\neq i} f(d)
\]
两边同时加上 \(S(n)\) 得:
\[\begin{aligned}2 S(n) &= 1 + \sum_{i=1}^n \sum_{d|i} f(d) \\&= 1 + \sum_{d=1}^n \sum_{i=1}^{\left\lfloor \frac {n}{d} \right\rfloor} f(i) \\&= 1 + \sum_{d=1}^n S\left(\left\lfloor \frac {n}{d} \right\rfloor\right)\end{aligned}
\]
于是有:
\[S(n) = 1 + \sum_{d=2}^n S\left(\left\lfloor \frac {n}{d} \right\rfloor\right)
\]
杜教筛即可。
代码
#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\n", F(n));
return 0;
}