P5325 【模板】Min_25 筛

· · 题解

P5325 【模板】Min_25 筛(PN 筛)

定义 \tt{Powerful\ Number} 为每个质因子项次数至少为 2 的数。

显然的一点,任意一个 \tt{Powerful\ Number} 可以被表示为 a^2b^3。而在 n 以内的 \tt{Powerful\ Number} 的数量即为:

\sum_{a^2b^3\le n} 1\\ =\sum_{a=1}^{\sqrt n}\sqrt[3]{\lfloor\frac n{a^2}\rfloor}\\ \approx \int_1^{\sqrt{n}} \frac {\sqrt[3]{n}}{\sqrt[3]{x}} \text{d} x\\ \approx (3\sqrt[6]{n}-3)\sqrt[3]n\\ =O(\sqrt{n})

这是一个重要的结论,即在 n 以内的 \tt{Powerful\ Number} 的数量是 \sqrt n 级别的。

回到本题,要求积性函数 f(p^k)=p^k(p^k-1)p 为质数)的前缀和。

g(x)=\varphi(x)x。因为 p 为质数,因此有 \varphi(p)=p-1,同时便满足 f(p)=g(p)

f=g*h(狄利克雷卷积),则:

f(x)=\sum_{d|x} g(d)h(\frac xd)\\ f(p)=g(1)h(p)+g(p)h(1)\\ \because f(p)=g(p),g(1)=h(1)=1,\\ \therefore f(p)=h(p)+f(p),h(p)=0.

同时由上也可以得出 h 为积性函数。因此只有当 x\tt{Powerful\ Number} 时才可能满足 h(x)\ne0。继续推式子:

f(p^k)=(g*h)(p^k)\\ =\sum_{d|p^k} g(d)h(\frac {p^k}d)\\ =\sum_{i=0}^k g(p^i)h(p^{k-i})\\ g(p^i)=\varphi(p^i)p^i=(p^i-p^{i-1})p^i=(p-1)p^{2i-1}\\ g(1)=1\\ p^k(p^k-1)=h(p^k)+\sum_{i=1}^k(p-1)p^{2i-1}h(p^{n-i})\\ p^k(p^k-1)=h(p^k)+\sum_{i=0}^{k-1}(p-1)p^{2k-2i-1}h(p^i)\\ h(p^k)=p^k(p^k-1)-\sum_{i=0}^{k-1}(p-1)p^{2k-2i-1}h(p^i)\\

于是我们得到了 h(p^k) 的递推式,直接递推即可算出。

$$ \sum_{ij\le n}h(i)g(j)\\ =\sum_{i=1}^nh(i)\sum_{j=1}^{\lfloor\frac ni\rfloor}g(j) $$ 后半部分可以使用杜教筛算出,而又因为 $\tt{Powerful\ Number}$ 的数量在 $O(\sqrt n)$ 级别,因此只会有 $O(\sqrt n)$ 个 $h(i)$ 有值,直接算即可,时间复杂度为 $O(n^{\frac34})$。 ## AC Code ```cpp #include <bits/stdc++.h> #define int long long using namespace std; const int N = 2e6 + 5; const int mod = 1e9 + 7 , inv3 = (mod + 1) / 3; int n , m , k; int power (int x , int y) { int ans = 1; while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod; y >>= 1; } return ans; } int Sum1 (int n) { n %= mod; return n * (n + 1) / 2 % mod; } int Sum2 (int n) { n %= mod; return n * (n + 1) / 2 % mod * (2 * n + 1) % mod * inv3 % mod; } namespace PhiSum { int sum[N]; unordered_map <int , int> f; int S (int x) { if (x < N) return sum[x]; if (f.count (x)) return f[x]; int ans = 0 , nxt , v; for (register int i = 2;i <= x;) { v = x / i , nxt = x / v; ans = (ans + S (v) * (Sum1 (nxt) - Sum1 (i - 1))) % mod; i = nxt + 1; } return f[x] = (Sum2 (x) - ans) % mod; } bool vis[N]; int pri[N] , ph[N]; void init () { sum[1] = 1; for (int i = 2;i < N;i ++) { if (!vis[i]) pri[++ m] = i , ph[i] = i - 1; for (int j = 1 , k;j <= m && (k = pri[j] * i) < N;j ++) { vis[k] = 1; if (i % pri[j] == 0) { ph[k] = ph[i] * pri[j]; break; } ph[k] = ph[i] * ph[pri[j]]; } sum[i] = sum[i - 1] + ph[i] * i; sum[i] %= mod; } } } int a[N] , h[N] , s[N]; signed main () { ios::sync_with_stdio (0); cin.tie (0) , cout.tie (0); cin >> n; PhiSum::init (); a[++ k] = 1; h[k] = s[0] = 1; for (int i = 1;i <= m;i ++) { int pr = PhiSum::pri[i] , Mul2 = pr * pr; if (Mul2 > n) break; __int128 Mul = Mul2; for (int j = 2;Mul <= n;j ++) { s[j] = Mul % mod * (Mul - 1) % mod; for (int l = 0;l < j;l ++) s[j] = (s[j] - (pr - 1) * power (pr , 2 * j - 2 * l - 1) % mod * s[l] % mod); s[j] %= mod; Mul *= pr; } int K = k; for (int j = 1;j <= K;j ++) { if (a[j] * pr > n) continue; int mul = a[j] * Mul2; int cc = 2; while (mul <= n) { a[++ k] = mul; h[k] = h[j] * s[cc] % mod; cc ++; mul *= pr; } } } int ans = 0; for (int i = 1;i <= k;i ++) ans = (ans + h[i] * PhiSum::S (n / a[i])) % mod; cout << (ans + mod) % mod; return 0; } ```