深刻认识到自己是彩笔的这一事实。
Powerful Number:所有质因子次数都不为 1 的数。
有一个结论是小于等于 $n$ 的 Powerful Number 个数是 $O(\sqrt n)$ 的。
可以用来求积性函数前缀和。假设我们正在求 $F$ 的前缀和,然后现在我们有一个积性函数 $G$ 满足 $\forall p \in \mathbb{P},F§=G§$,且 $G$ 的前缀和可次线性求。然后我们现在有个函数 $H$ 满足 $F=G*H$(狄利克雷卷积),显然 $H$ 也是积性函数。然后根据杜教筛那套推法,我们有:
$$
\sum_{i=1}^nF(n)=\sum_{i=1}^nH(n)\sum_{j=1}^{\left\lfloor\frac ni\right\rfloor}G(j)\tag 1
$$
我们观察到:
$$
F(p)=G(1)H(p)+G(p)H(1)
$$
又因为 $F§=G§$,则我们有 $H§=0$。然后容易发现 $H$ 只在 Powerful Number 处值非 0,在非 Powerful Number 的地方由于 $H$ 是积性函数则它被分解为了 $H(\frac np)\cdot H§=H(\frac np)\cdot 0=0$。于是我们可以直接 dfs 出所有的 Powerful Number 并代到 $(1)$ 式里面算。现在问题是怎么算 $H$。我们发现:
$$
\begin{aligned}
F(n)&=\sum_{d|n}G(d)\cdot H\left(\frac nd\right)\\
F(n)&=H(n)+\sum_{d|n,d\ne1}G(d)\cdot H\left(\frac nd\right)\\
H(x)&=F(n)-\sum_{d|n,d\ne1}G(d)\cdot H(\frac nd)
\end{aligned}
$$
实际上我们只需要算 $H(p^k)$,毕竟我们有个枚举 Powerful Number 的过程,乘起来就行。
$$
H(p^k)=F(p^k)-\sum_{j=1}^kG(p^j)H(p^{k-j})
$$
好算。就是写着不怎么方便
P5325 【模板】Min_25 筛
$f$ 是积性函数,且 $f(p^k)=p^k(p^k-1)$。求
$$
\sum_{i=1}^nf(i)
$$
对 $10^9+7$ 取模。
$1\le n\le 10^{10}$
我们设 $G(x)=x\varphi(x)$(注意 $G(x)=x(x-1)$ 不是积性函数),然后按照上面一样做就好了。$G(x)$ 的前缀和可以用杜教筛。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
   |  #include <cmath> #include <cstdio>
  typedef long long qe;
  const int $L = 5624000; const int $p = $L; const int $pk = 35; const int mod = 1000000007; const int inv6 = 166666668;
  inline int add(int x, int y) { return (x += y) >= mod? x - mod: x; } inline void Add(int &x, int y) { if ((x += y) >= mod) x -= mod; } inline int sub(int x, int y) { return (x -= y) < 0? x + mod: x; } inline void Sub(int &x, int y) { if ((x -= y) < 0) x += mod; } inline int div2(int x) { return ((x & 1)? x + mod: x) >> 1; }
  qe n; int L, ans; bool co[$L]; int pr[$p], G[$L], Hp[$L][$pk]; inline void sieve() { 	G[1] = 1; 	for (int i = 2; i <= L; ++i) { 		if (!co[i]) { pr[++pr[0]] = i; G[i] = i - 1; } 		for (int j = 1, k; j <= pr[0] && (k = i * pr[j]) <= L; ++j) { 			co[k] = 1; 			if (i % pr[j]) G[k] = (qe)G[i] * (pr[j] - 1) % mod; 			else { G[k] = (qe)G[i] * pr[j] % mod; break; } 		} 		G[i] = (G[i - 1] + (qe)G[i] * i) % mod; 	} 	qe tmp[$pk]; 	for (int i = 1; i <= pr[0]; ++i) { 		qe w = (qe)pr[i] * pr[i]; if (w > n) break; 		const int del = w % mod; 		auto &cur = Hp[i]; 		cur[0] = tmp[0] = 1; 		tmp[1] = (qe)pr[i] * (pr[i] - 1) % mod; 		for (int j = 2; w <= n; ++j, w *= pr[i]) { 			tmp[j] = (qe)tmp[j - 1] * del % mod; 			cur[j] = (qe)w % mod * (w % mod - 1) % mod; 			for (int k = 1; k <= j; ++k) 				Sub(cur[j], (qe)tmp[k] * cur[j - k] % mod); 		} 	} } inline int sum1(qe x) { x %= mod; return x * (x + 1) / 2 % mod; } inline int sum2(qe x) { x %= mod; return x * (x + 1) % mod * (x * 2 + 1) % mod * inv6 % mod; } int S(qe n) { 	static int mem[2005]; 	if (n <= L) return G[n]; 	const int index = ::n / n; 	if (mem[index]) return mem[index]; 	int ans = sum2(n), lst = 1; 	for (qe l = 2, r; l <= n; l = r + 1) { 		const qe t = n / l; r = n / t; 		const int cur = sum1(r); 		Sub(ans, (qe)sub(cur, lst) * S(t) % mod); 		lst = cur; 	} 	return mem[index] = ans; } void dfs(qe x, int H, int lst) { 	Add(ans, (qe)H * S(n / x) % mod); 	const qe lim = n / x; 	for (int i = lst + 1; i <= pr[0]; ++i) { 		if ((qe)pr[i] * pr[i] > lim) return; 		qe cur = (qe)x * pr[i] * pr[i]; 		for (int j = 2; cur <= n; ++j, cur *= pr[i]) 			dfs(cur, (qe)H * Hp[i][j] % mod, i); 	} } int main() { 	scanf("%lld", &n); 	L = std::max((int)std::pow(n, 0.675) + 5, 100); 	sieve(); 	dfs(1, 1, 0); 	printf("%d\n", ans); }
 
  |