Min_25 筛学习笔记

· · 个人记录

问题描述

\sum_{i=1}^{n}f(i) \pmod{Mod}

其中 f 是一个积性函数

算法解决

主要思路就是将积性函数分为三个部分来求

  1. i 是质数。
  2. i 是合数。
  3. i=1

    它的思想类似 DP

#### $\text{step1}

g(n)=\sum\limits_{p\leq n}f(p)

我们首先需要了解一下埃氏筛法(圈一个质数,划去它的倍数)引用。

先来考虑如何表示一个埃氏筛的状态。

那么用前 k 个质数来筛,最后没有被叉掉的数的最小质因子必然大于 p_k

g(n,k) 表示 2 \sim n 中的所有质数或最小质因子大于 p_k 的数的 f 值和。

怎么转移?

考虑埃氏筛的过程,选定一个质数后,直接从它的平方开始筛。

所以当 p_k^2 > n 时,g_{n,k}=g_{n,k-1}。(p_k 指第 k 个质数)。

否则我们就一定会再叉掉一些数,减掉一部分 f 值。

\large g(n,k)=g(n,k-1)-f(p_k)\cdot \left(g(\lfloor\frac{n}{p_k}\rfloor,k-1)-g(p_k-1,k-1)\right)

这里利用了 f 是积性函数的条件。

理解:用前 $k-1$ 个质数来筛,把没筛掉的数,作为 $p_k$ 的倍数(这个倍数一定会与前 $k-1$ 个质数互质且这个倍数 $\cdot p_k < n$)来确定 $p_k$ 需要筛哪些点。 由于前 $k-1$ 个质数也是剩下的数,所以还要加上 $f(p_k) \cdot g_{p_k-1,k-1}$(也就是 $f(p_k)\cdot \sum\limits_{i=1}^{k-1}f(p_i)$,即 $p_k$ 与前 $k-1$ 个质数的组合)。 #### $\text{step2}

s(n)=\sum\limits_{i\leq n}f(i)

s(n,k) 表示 1 \sim n 中最小质因子大于 p_k 的数的 f 值和。

那么有转移:

\large s(n,j)=g(n)-g(p_j)+\sum_{j<k \operatorname{and}p_k\leq \sqrt{n}}\sum_{1 \leq e \operatorname{and} p_k^e \leq n} f(p_k^e)\left(s\left(\lfloor\frac{n}{p_k^e}\rfloor,k\right) +[e \ne 1]\right)

意义为:分质数,合数考虑贡献。

质数的贡献我们已经搞好了,为 g(n)-g(p_j),即 \sum\limits_{p\leq n}f(p)-\sum\limits_{i=1}^{j-1}f(p_i)

合数的话,我们需要枚举最小质因子及其次数,即 k>jp_k,再枚举次数 e

由于是积性函数,我们直接将 f(p_k^e) 提出。

值得注意的是,形如 p^k,k>1 的数我们既没有在质数出枚举到,也没有在合数处提出 p_k^e 后枚举到,所以需要加上个 [e \ne 1]

转移二:

s(n,j)=\sum_{i=1}^{n}f(i)[i 是质数或其最小质因子 \ge p_j]

s(n,j)=s(n,j+1)+\sum_{p_{j+1} \leq \sqrt{n}}\sum_{1 \leq e \operatorname{and} p_{j+1}^{e}\leq n}f(p_{j+1}^{e})\left(s\left(\lfloor\frac{n}{p_{j+1}^{e}\rfloor},j+1\right)-g(p_{j+1}) \right)+f_{p_{j+1}^{e+1}}

这种方法虽然实际效率劣于方法一,但这种方法不仅算出了 s(n),也顺带计算出了所有 s(\lfloor\frac{n}{x}\rfloor),这是方法一做不到的。

\text{step3}

最后加上 f(1) 即可。

总时间复杂度约为 \mathcal O(\frac{n^{0.75}}{\log n})

实现细节和代码

P5325 【模板】Min_25筛

定义积性函数 f(x),且 f(p^k)=p^k(p^k-1)p 是一个质数),求

\sum_{i=1}^n f(i)

10^9+7 取模。

首先,由题意有,$f(p)=p^2-p$,维护一下 $g_1=p$ 和 $g_2=p^2$ 的前缀和然后用 $\text{Min25}$ 筛即可。 细节: * 在求 $g$ 的时候空间太大了,需要优化,因为 $g$ 都是由 $\frac{n}{k}$ 处推来的,众所周知 $\frac{n}{k}$ 的取值只有 $2\sqrt{n}$ 种情况,让 $id1_k$ 记录 $k\le\sqrt n$,$id2_k$ 记录 $\frac{n}{k} \le \sqrt n$,所以可以只枚举这 $2\sqrt n$ 种情况。 * **拆成的 $g$ 必须保证是完全积性函数,不然不可递推。** ```cpp #include <bits/stdc++.h> using namespace std; template <typename T> inline void read(T &t) { t = 0; char c = getchar(); int f = 1; while (c < '0' || c > '9') { if (c == '-') f = -f; c = getchar(); } while (c >= '0' && c <= '9') { t = (t << 3) + (t << 1) + c - '0'; c = getchar(); } t *= f; } template <typename T, typename... Args> inline void read(T &t, Args &...args) { read(t); read(args...); } template <typename T> inline void write(T x) { if (x < 0) { x = -x; putchar('-'); } if (x > 9) write(x / 10); putchar(x % 10 + '0'); } #define ll long long const int _ = 2e5 + 7; const int mod = 1e9 + 7; bool v[_]; ll tot, p[_], n, sq, w[_], m, sum1[_], sum2[_], g1[_], g2[_], id1[_], id2[_]; // id1 id2 如文中所示 w[k] 为第 k 个需要处理的数 // 文中的 g 为 g2 - g1, g1 : f(k) = k, g2: f(k) = k ^ 2 // sum1 : 质数前缀和 ; sum2: 质数平方前缀和 void pre() // 线性筛 { for (int i = 2; i <= sq; ++i) { if (!v[i]) { p[++tot] = i; sum1[tot] = (sum1[tot - 1] + p[tot]) % mod; sum2[tot] = (sum2[tot - 1] + p[tot] * p[tot]) % mod; } for (int j = 1; p[j] * i <= sq && j <= tot; j++) { v[p[j] * i] = 1; if (i % p[j] == 0) break; } } } ll getid(ll x) { if (x <= sq) return id1[x]; else return id2[n / x]; } ll f1(ll x) // 1 ~ x 前缀和 { x %= mod; return x * (x + 1) / 2 % mod; } ll f2(ll x) // 1 ~ x 前缀平方和 { x %= mod; return x * (x + 1) % mod * (2 * x % mod + 1) % mod * 166666668 % mod; } ll S(ll x, int j) { if (p[j] > x) return 0; ll Ans = ((g2[getid(x)] - g1[getid(x)] + mod) % mod - (sum2[j] - sum1[j] + mod) % mod + mod) % mod; for (int i = j + 1; i <= tot && p[i] * p[i] <= x; ++i) for (ll e = 1, sp = p[i]; sp <= x; sp *= p[i], ++e) Ans = (Ans + sp % mod * (sp % mod - 1) % mod * (S(x / sp, i) + (e > 1)) % mod) % mod; return Ans; } signed main() { read(n); sq = sqrt(n); pre(); for (ll l = 1, r; l <= n; l = r + 1) { r = (n / (n / l)), w[++m] = n / l; g1[m] = f1(w[m]) - 1, g2[m] = f2(w[m]) - 1; // 处理 g(?, 0) if (w[m] <= sq) id1[w[m]] = m; else id2[n / w[m]] = m; } for (int i = 1; i <= tot; ++i) // dp 处理 g 函数 { for (int j = 1; j <= m && p[i] * p[i] <= w[j]; ++j) { g1[j] = (g1[j] - p[i] * (g1[getid(w[j] / p[i])] - sum1[i - 1]) % mod + mod) % mod; g2[j] = (g2[j] - p[i] * p[i] % mod * (g2[getid(w[j] / p[i])] - sum2[i - 1]) % mod + mod) % mod; } } write((S(n, 0) + 1ll) % mod), putchar('\n'); return 0; } ``` ### 例题 #### [P4213 【模板】杜教筛(Sum)](https://www.luogu.com.cn/problem/P4213) 给定一个正整数 $n$,求 $$ ans1=\sum_{i=1}^{n}\varphi(i)\\ ans2=\sum_{i=1}^{n}\mu(i) $$ 先看 $\varphi$,由 $\varphi(p)=p-1$,我们可以维护 $p$ 和 $1$ 的前缀和。 另外,由 $\varphi(p^c)=p^{c-1}(p-1)$,可知,质数的整次幂的函数值也很好求。 然后是 $\mu$,显然 $\mu(p)=-1$,我们可以维护 $1$ 的前缀和,然后取反。 另外,$\mu(p^k)=0(k>1)$,因此求 $s$ 时不需要枚举最小质因子的次数。 [CODE](https://www.luogu.com.cn/paste/jc7tyj9v) #### [loj 6235 区间素数个数](https://loj.ac/p/6235) 求 $1 \sim n$ 之间素数个数。 $2 \leq n \leq 10^{11}$。 求质数个数,联想到 $\text{Min25}$ 筛的第一步。相当于求 $f(p)=1$ 这个函数在质数处取值的前缀和。 [CODE](https://www.luogu.com.cn/paste/wi6kpie1) #### [loj 6181 某个套路求和题](https://loj.ac/p/6181) 记 $$ f(n)=\prod_{d|n}\mu(d) $$ 求 $$ \sum_{i=1}^{n}f(i) \pmod{998244353} $$ $1 \leq n \leq 10^{10}$。 易得 $$ ans=\sum_{i=1}^{n}\mu(i)^2-\sum_{i=1}^{n}2\times [i \in \text{primes}] $$ 套个 $\text{Min25}$ 筛即可。 [CODE](https://www.luogu.com.cn/paste/uwnqderc) #### [loj 6053 简单的函数](https://loj.ac/p/6053) > 求积性函数 $f(p^c)=p\oplus c,p\in \text{primes}$ 的前缀和 $\pmod{10^9+7}$。 > > $1 \leq n \leq 10^{10}$。 易得 $$ f(p)=\begin{cases}p-1 & p \ne2 \\p+1& p=2\end{cases} $$ 我们可以先把 $f(p)$ 当成 $p-1$,然后维护 $p$ 和 $1$ 的前缀和,最后特判即可。 注意,我们应当保证拆成的若干个函数是完全积性函数。 [CODE](https://www.luogu.com.cn/paste/ir7nregx) [SP34096 DIVCNTK - Counting Divisors (general)](https://www.luogu.com.cn/problem/SP34096) 求 $\sum\limits_{i=1}^{n}d(i^k) \pmod{2^{64}}$。 其中 $d(i)$ 表示 $i$ 的约数个数。 多测。 ![](https://img-blog.csdnimg.cn/img_convert/9111f082afdc7465f9a3d7a8265ff3f0.png) 设 $f(x)=d(x^k)$。 则 $f$ 满足一下几条性质: * $f(1)=1$。 * $f(p)=k+1,p\in \text{primes}$。 * $f(p^c)=kc+1$。 * $f(ab)=f(a)\times f(b),\gcd(a,b)=1$。 套个 $\text{Min25}$ 筛即可。 [CODE](https://www.luogu.com.cn/paste/3odjq9r6) 多倍经验(修改一下 $k$ 的值即可)。 [SP20173 DIVCNT2 - Counting Divisors (square)](https://www.luogu.com.cn/problem/SP20173) [SP20174 DIVCNT3 - Counting Divisors (cube)](https://www.luogu.com.cn/problem/SP20174) ### 总结 用 $\text{Min25}$ 做题主要是要想清楚两个问题: 1. 该函数在质数处的取值怎么求和? 2. 质数的次幂处的取值 $f(p^c)$ 能否快速求?