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;
}
posted @ 2020-01-17 20:39  xgzc  阅读(267)  评论(0编辑  收藏  举报