P5325 【模板】Min_25 筛

· · 题解

0x00 引言

Min_25 筛可以在 \mathcal{O}\left( \dfrac{n^\frac{3}{4}}{\log n} \right)\Theta(n^{1 - \epsilon}) 的复杂度下求一类积性函数的前缀和。

以下是前提条件。

  1. 对于质数 pf(p) 是关于 p 的可快速求值的完全积性函数之和(例如多项式)。

  2. 对于质数 pf(p^c) 可快速求值。

0x10 约定

0x20 正文

我们要计算的是 \mathrm{Ans} = \displaystyle\sum\limits_{i=1}^{n}f(i)

注意到 F_1(n) = \displaystyle\sum\limits_{\substack{i \in [2,n] \\ \operatorname{lpf}(i) \ge 2}}f(i) = \displaystyle\sum\limits_{i=2}^{n}f(i)

于是 \mathrm{Ans} = F_1(n) + f(1) = F_1(n) + 1。(积性函数 f(1) = 1

考虑如何求出 F_k(n)

首先,若 n < p_k,则 F_k(n) = 0

否则,设 F_k(n) = \displaystyle\sum\limits_{\substack{t \in [2,n] \\ \operatorname{lpf}(t) \ge p_k}}f(t)

考虑所有可能的 t。这些 t 一部分为质数,另一部分为合数。

::::info[当 t 为质数时]{open}

t = p_i

\operatorname{lpf}(t) = p_i

t \in [2,n],有 p_i \le n

\operatorname{lpf}(t) \ge p_k,有 p_i \ge p_k

我们要求的是 p_k \le p_i \le nf(p_i) 之和。

$p_i < p_k$,即 $p_i \le p_{k-1}$ 的 $f(p_i)$ 之和为 $\displaystyle\sum\limits_{p_i \le p_{k-1}}f(p_i) = F_{\text{prime}}(p_{k-1})$。 因此,所有质数 $t$ 对 $F_k(n)$ 的贡献为: $$F_{\text{prime}}(n) - F_{\text{prime}}(p_{k-1}).$$ :::: ::::info[当 $t$ 为合数时]{open} 设 $t = p_i^c \cdot m$,满足 $\operatorname{lpf}(t) = p_i$ 且 $p_i \nmid m$。 考虑 $p_i$ 的取值范围。 首先 $p_i \ge p_k$,即 $i \ge k$。 由于 $\operatorname{lpf}(t) = p_i$,故 $p_i^2 \le t$。而 $t \le n$,故 $p_i^2 \le n$。 按 $m$ 的值分讨。 :::info[当 $m=1$ 时]{open} 此时 $t = p_i^c$。 考虑 $c$ 的取值范围。 首先 $p_i^c \le n$。 由于 $p_i^c$ 是合数,故 $c \ge 2$。 枚举 $p_i$ 和 $p_i$ 的次数 $c$,这部分的贡献为: $$\sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 2\\p_i^c \le n}}f(p_i^c).$$ 将 $c$ 用 $c+1$ 代换: $$\sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 1\\p_i^{c+1} \le n}}f(p_i^{c+1}).$$ ::: :::info[当 $m \ge 2$ 时]{open} 考虑 $c$ 的取值范围,显然有 $c \ge 1$ 且 $p_i^c \le n$。 考虑 $m$ 的约束条件。 首先 $t = p_i^c \cdot m \le n$,即 $m \le n/p_i^c$。 由于 $\operatorname{lpf}(t) = p_i$ 且 $p_i \nmid m$,所以 $\operatorname{lpf}(m) > p_i$,即 $\operatorname{lpf}(m) \ge p_{i+1}$。 故 $m$ 满足:$2 \le m \le n/p_i^c$ 且 $\operatorname{lpf}(m) \ge p_{i+1}$。 这些 $m$ 的 $f(m)$ 之和为 $\displaystyle\sum\limits_{\substack{m \in [2,n/p_i^c] \\ \operatorname{lpf}(m) \ge p_{i+1}}}f(m) = F_{i+1}(n/p_i^c)$。 枚举 $p_i$、$p_i$ 的次数 $c$ 和 $m$,这部分的贡献为: $$\begin{aligned} &\ \ \ \ \,\sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 1\\p_i^c \le n}}\sum\limits_{\substack{m \in [2,n/p_i^c] \\ \operatorname{lpf}(m) \ge p_{i+1}}}f(p_i^c \cdot m)\\ &= \sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 1\\p_i^c \le n}}f(p_i^c)\sum\limits_{\substack{m \in [2,n/p_i^c] \\ \operatorname{lpf}(m) \ge p_{i+1}}}f(m)\\ &= \sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 1\\p_i^c \le n}}f(p_i^c)F_{i+1}(n/p_i^c). \end{aligned}$$ 考虑 $p_i^c \le n < p_i^{c+1}$ 的情况。 此时 $n/p_i^c < p_i$,而 $p_i < p_{i+1}$,故 $n/p_i^c < p_{i+1}$。 于是 $F_{i+1}(n/p_i^c)=0$。 因此当 $n \ge p_i^{c+1}$ 时,$F_{i+1}(n/p_i^c)$ 才可能有值。 将第二重求和的上界改为 $p_i^{c+1} \le n$,则这部分的贡献为: $$\sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 1\\p_i^{c+1} \le n}}f(p_i^c)F_{i+1}(n/p_i^c).$$ ::: 综上,所有合数 $t$ 对 $F_k(n)$ 的贡献为: $$\begin{aligned} &\ \ \ \ \,\sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 1\\p_i^{c+1} \le n}}f(p_i^{c+1}) + \sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 1\\p_i^{c+1} \le n}}f(p_i^c)F_{i+1}(n/p_i^c)\\ &=\sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 1\\p_i^{c+1} \le n}}\left( f(p_i^{c+1}) + f(p_i^c)F_{i+1}(n/p_i^c) \right). \end{aligned}$$ :::: 综上: $$F_k(n) = F_{\text{prime}}(n) - F_{\text{prime}}(p_{k-1}) + \sum\limits_{\substack{i \ge k\\p_i^2 \le n}}\sum\limits_{\substack{c \ge 1\\p_i^{c+1} \le n}}\left( f(p_i^{c+1}) + f(p_i^c)F_{i+1}(n/p_i^c) \right).$$ 其中,$F_{\text{prime}}(p_{k-1})$ 可在线性筛时维护得出,$f(p_i^c)$ 和 $f(p_i^{c+1})$ 可直接计算。难点在于 $F_{\text{prime}}(n)$。 假设现在已经求出了所有 $F_{\text{prime}}(n)$,那么有两种方式可以求出所有 $F_k(n)$: 1. 直接按照递推式递归计算。 2. 从大到小枚举 $p_i$ 转移,仅当 $p_i^2 < n$ 时转移增加值不为 $0$,故按照递推式后缀和优化即可。 --- 现在考虑如何求出所有 $F_{\text{prime}}(n)$。 观察求 $F_k(n)$ 的过程,易得 $F_k(n)$ 只在形如 $n' = n/i$ 的点有值,$F_{\text{prime}}(n)$ 亦是如此。 :::info[证明]{open} 考虑类似于数学归纳法的证明方法。 首先 $n = n/1$,是 $n/i$ 的形式。 递归时,第一步 $n' = n/p_i^c$ 仍为 $n/i$ 的形式。 后续递归中,$n'/j = (n/i)/j = n/(ij)$,依然是 $n/i$ 的形式。 ::: 这些 $n'$ 必然在集合 $S = \{ 1,2,3,\cdots,\lfloor\sqrt{n}\rfloor,n/\lfloor\sqrt{n}\rfloor,\cdots,n/3,n/2,n \}$ 中。 其中 $\lvert S \rvert = \Theta(\sqrt{n})$。 考虑如何求出所有 $F_{\text{prime}}(n')$。 设 $f(p) = \displaystyle\sum\limits_{i=1}^{r}a_i p^{c_i}$。 则: $$\begin{aligned} F_{\text{prime}}(n') &= \sum\limits_{p \le n'}f(p)\\ &= \sum\limits_{p \le n'} \sum\limits_{i=1}^{r}a_i p^{c_i}\\ &= \sum\limits_{i=1}^{r}a_i \sum\limits_{p \le n'} p^{c_i}. \end{aligned}$$ 考虑对于所有 $n'$,求出形如 $\displaystyle\sum\limits_{p \le n'} p^c$ 的式子。 设 $g(p) = p^c$。 设 $G_{\text{prime}}(n) = \displaystyle\sum\limits_{p \le n}g(p)$。 设 $G_k(n) = \displaystyle\sum\limits_{\substack{i \in [2,n] \\ \operatorname{lpf}(i) > p_k \lor \operatorname{isprime}(i)}} g(i)$,即**埃氏筛**第 $k$ 轮筛完后剩余的数的 $g(i)$ 之和。 显然 $G_{\text{prime}}(n)$ 与 $G_k(n)$ 也仅在形如 $n' = n/i$ 的点上有值。 考虑如何求出所有 $G_{\text{prime}}(n')$。(求出所有 $G_{\text{prime}}(n')$ 后即可得到所有 $F_{\text{prime}}(n')$) 对于合数 $x \le n$,必然有 $\operatorname{lpf}(x) \le \sqrt{x} \le \sqrt{n}$。 设 $\ell(n)$ 为小于等于 $\sqrt{n}$ 的最大质数的下标,则 $G_{\text{prime}}(n) = G_{\ell(n)}(n)$。因为在埃氏筛进行 $\ell(n)$ 轮后,剩下的均为质数。 考虑递推计算 $G_{\ell(n)}(n)$。 先算出 $G_0(n) = \displaystyle\sum\limits_{\substack{i \in [2,n] \\ \operatorname{lpf}(i) > 1 \lor \operatorname{isprime}(i)}} g(i) = \displaystyle\sum\limits_{i=2}^{n} g(i)$。(前面规定了 $p_0 = 1$) 考虑如何转移。 埃氏筛中第 $k$ 轮用 $p_k$ 筛去了**未被筛过的** $p_k$ 的倍数,设其为 $x = p_k \cdot m$。 满足: - $\operatorname{lpf}(x) = p_k$。 - $\operatorname{lpf}(m) \ge p_k$。 考虑 $p_k^2$ 和 $n$ 的大小关系。 :::info[当 $p_k^2 > n$ 时]{open} 对于合数 $x \le n$,$\operatorname{lpf}(x) \le \sqrt{n}$。而 $n < p_k^2$,即 $\sqrt{n} < p_k$,也就是说 $\operatorname{lpf}(x) < p_k$。故 $\operatorname{lpf}(x)$ 不可能等于 $p_k$。 也就是说 $\ell(n)$ 就等于 $k-1$,即在上一轮就已经筛出了所有质数。此时终止递推。 后续 $k > \ell(n)$ 的 $G_k(n)$ 均等于 $G_{\ell(n)}(n)$。 ::: :::info[当 $p_k^2 \le n$ 时]{open} 此时 $G_k(n)$ 等于 $G_{k-1}(n)$ 减去这一轮被筛去的 $x$ 的 $g$ 值之和。 考虑 $m$ 的约束条件。 首先 $x = p_k \cdot m \le n$,即 $m \le n/p_k$。 由 $\operatorname{lpf}(m) \ge p_k$,显然有 $m \ge p_k$。 $\operatorname{lpf}(m) \ge p_k$ 即 $\operatorname{lpf}(m) > p_{k-1}$。 故 $m$ 满足:$p_k \le m \le n/p_k$ 且 $\operatorname{lpf}(m) > p_{k-1}$。 这些 $m$ 的 $g$ 值之和为 $\displaystyle\sum\limits_{\substack{m \in [p_k,n/p_k] \\ \operatorname{lpf}(m) > p_{k-1}}} g(m)$。 注意到 $G_{k-1}(n/p_k) = \displaystyle\sum\limits_{\substack{i \in [2,n/p_k] \\ \operatorname{lpf}(i) > p_{k-1} \lor \operatorname{isprime}(i)}} g(i)$。 考虑利用 $G_{k-1}(n/p_k)$ 统计 $m$ 的 $g$ 值之和。 我们发现,$G_{k-1}(n/p_k)$ 多统计了 $[2,p_k)$ 中的质数的 $g$ 值,即 $G_{\text{prime}}(p_{k-1})$。($[2,p_k)$ 中的质数即 $[2,p_{k-1}]$ 中的质数) 故这些 $m$ 的 $g$ 值之和为: $$G_{k-1}(n/p_k) - G_{\text{prime}}(p_{k-1}).$$ 由于 $g$ 是完全积性函数,故 $g(p_k \cdot m) = g(p_k)g(m)$。 故这一轮被筛去的 $x$ 的 $g$ 值之和为: $$\begin{aligned} \sum\limits_{\substack{m \in [p_k,n/p_k] \\ \operatorname{lpf}(m) > p_{k-1}}} g(p_k \cdot m) &= g(p_k) \sum\limits_{\substack{m \in [p_k,n/p_k] \\ \operatorname{lpf}(m) > p_{k-1}}} g(m)\\ &= g(p_k)\left( G_{k-1}(n/p_k) - G_{\text{prime}}(p_{k-1}) \right). \end{aligned}$$ 于是: $$G_k(n) = G_{k-1}(n) - g(p_k)\left( G_{k-1}(n/p_k) - G_{\text{prime}}(p_{k-1}) \right).$$ ::: 实现时,用两重循环分别枚举 $p_k$ 和可能的 $n'$。对于每一个 $n'$,从 $G_0(n')$ 推到 $G_{\ell(n')}(n')$ 即可得到 $G_{\text{prime}}(n')$。具体见代码。 其中 $g(p_k)$ 可以直接计算,$G_{\text{prime}}(p_{k-1})$ 可在线性筛时维护得出。 ## 0x30 复杂度分析 对于 $F_k(n)$ 的计算,第一种方法的时间复杂度被证明为 $\Theta(n^{1 - \epsilon})$ $^{\textup{\textmd{\textsf{[1]}}}}$;第二种方法本质为洲阁筛的第二部分,其时间复杂度被证明为 $\mathcal{O}\left( \dfrac{n^\frac{3}{4}}{\log n} \right)$ $^{\textup{\textmd{\textsf{[2]}}}}$。 对于 $F_{\text{prime}}(n)$ 的计算,其实现与洲阁筛的第一部分相同。 考虑对于每个 $n' = n/i$,只有在枚举满足 $p_k^2 \le n'$ 的 $p_k$ 转移时会对复杂度产生贡献。则时间复杂度可估计为: $$\begin{aligned} T(n) &= \sum\limits_{i^2 \le n}\mathcal{O}\left( \pi \left( \sqrt{i}\right) \right) + \sum\limits_{i^2 \le n}\mathcal{O}\left( \pi \left( \sqrt{\frac{n}{i}} \right) \right)\\ &= \sum\limits_{i^2 \le n}\mathcal{O}\left( \frac{\sqrt{i}}{\ln \sqrt{i}} \right) + \sum\limits_{i^2 \le n}\mathcal{O}\left( \frac{\sqrt{\frac{n}{i}}}{\ln \sqrt{\frac{n}{i}}} \right)\\ &= \mathcal{O}\left( \int_{1}^{\sqrt{n}} \frac{\sqrt{\frac{n}{x}}}{\log \sqrt{\frac{n}{x}}} \mathrm{d}x\right)\\ &= \mathcal{O}\left( \dfrac{n^\frac{3}{4}}{\log n} \right). \end{aligned}$$ 空间复杂度显然为 $\Theta(\sqrt{n})$。 ## 0x40 代码实现 本题中 $f(p) = p(p-1) = p^2 - p$。 我们需要分别维护 $g(p) = p$ 和 $g(p) = p^2$ 对应的 $G_{\text{prime}}$ 值与 $G_k$ 值。 令 $B \gets \lfloor \sqrt{n} \rfloor$。 首先预处理出 $\le B$ 的质数,同时维护这些质数的 $G_{\text{prime}}$ 值。其 $F_{\text{prime}}$ 值可由 $f$ 的每一项所对应的 $G_{\text{prime}}$ 值相加而得。 记 $s_i = G_{\text{prime}}(p_i)$。 然后进行一次数论分块,记录所有可能的 $n'$。设这些 $n'$ 中第 $i$ 大的为 $w_i$。 设 $w_i$ 的个数为 $\mathrm{tot}$。可以证明 $\mathrm{tot} \le 2\sqrt{n}$。 考虑如何通过 $n' = w_i$ 找到其编号 $i$。 对于 $n' = w_i \le B$,用数组 $\mathrm{id}_1$ 记录其编号 $i$,即 $\mathrm{id}_1(n') = i$。 对于 $n' = w_i > B$,用数组 $\mathrm{id}_2$ 记录其编号 $i$,即 $\mathrm{id}_2(n/n') = i$。($n/n' \in [1,B]$) 存储 $G_k(n')$ 时用 $n' = w_i$ 的编号 $i$ 作为索引。 对于每一个 $n'$,先算出 $G_0(n')$。 然后计算所有 $G_{\text{prime}}(n')$,即所有 $G_{\ell(n')}(n')$。 考虑两重循环,第一重循环枚举质数 $p_k$,第二重循环枚举 $n' = w_i$。按照递推式计算即可。注意在第二重循环时,由于 $w$ 数组单调递减,因此当 $p_k^2 > w_i$ 时,后面的 $w_{i+1}\sim w_{\mathrm{tot}}$ 均小于 $p_k^2$,此时应退出循环。 存储 $G_k(n)$ 的数组中 $k$ 这一维度可以滚动,甚至可以直接省去。由于 $w$ 数组单调递减,在计算 $G_k(n)$ 时 $G_k(n/p_k)$ 尚未被计算,若省去 $k$ 这一维度,此时数组中 $n/p_k$ 对应的位置存储的值恰为 $G_{k-1}(n/p_k)$。($G_{\ell(n/p_k)}(n/p_k)$ 亦等于 $G_{k-1}(n/p_k)$) 此时我们得到了所有 $G_{\text{prime}}(n')$,同时得到了所有 $F_{\text{prime}}(n')$。 最后,选用**第一种**计算 $F_k(n)$ 的方法递归计算 $F_1(n)$ 。 --- Code。 ```cpp line-numbers #include<bits/stdc++.h> #define int long long const int B=1e5+10; const int TT=1e9+7; using namespace std; int n,b,ans; int cnt,p[B]; bool vis[B]; int s1[B],s2[B]; // s1[i] 与 s2[i] 分别记录 g(p) = p 与 g(p) = p^2 的 G_prime(p[i]) int tot,w[B<<1]; // w[i] 为可能的 n',tot 为 w[i] 的个数 int id1[B],id2[B]; // id1[n] 与 id2[n/n'] 分别记录 n' = w[i] <= b 与 n' = w[i] > b 的编号 i int g1[B<<1],g2[B<<1]; // g1[i] 与 g2[i] 分别记录 g(p) = p 与 g(p) = p^2 的 G_k(w[i]),最后得到的是它们的 G_prime(w[i]) int inv2,inv6; inline int read(){ int ret=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+(ch&15),ch=getchar(); return ret*f; } int _sqrt(int x){ int ret=floor(sqrtl(x)); while((ret+1)*(ret+1)<=x)ret++; return ret; } int qpow(int x,int y){ x%=TT; int ret=1; while(y){ if(y&1)ret=ret*x%TT; x=x*x%TT; y>>=1; } return ret; } int get_id(int _n){ // n' 的编号 if(_n<=b)return id1[_n]; return id2[n/_n]; } int _sub(int x,int y){ // 带取模的减法 return ((x-y)%TT+TT)%TT; } void _init(){ inv2=qpow(2,TT-2),inv6=qpow(6,TT-2); // 计算 2 和 6 的逆元 for(int i=2;i<=b;i++){ if(!vis[i]){ p[++cnt]=i; s1[cnt]=(s1[cnt-1]+i)%TT; // 维护 g(p) = p 的 G_prime(p[i]) s2[cnt]=(s2[cnt-1]+i*i%TT)%TT; // 维护 g(p) = p^2 的 G_prime(p[i]) } for(int j=1;j<=cnt&&i*p[j]<=b;j++){ vis[i*p[j]]=1; if(!(i%p[j]))break; } } for(int l=1,r;l<=n;l=r+1){ // 数论分块找到所有 n' 的可能值 r=n/(n/l); int _n=n/l; // n' = n/l 为有效值 w[++tot]=_n; // 记录 w[i] = n' if(_n<=b)id1[_n]=tot; // 记录 n' = w[i] 的编号 else id2[n/_n]=tot; _n%=TT; g1[tot]=_sub(_n*(_n+1)%TT*inv2%TT,1); // 计算 g(p) = p 的 G_0(w[i]) g2[tot]=_sub(_n*(_n+1)%TT*(_n*2+1)%TT*inv6%TT,1); // 计算 g(p) = p^2 的 G_0(w[i]) } for(int k=1;k<=cnt;k++){ // 第一层循环枚举 p[k] for(int i=1;i<=tot&&p[k]*p[k]<=w[i];i++){ // 第二层循环枚举 n' = w[i],p[k]*p[k] <= w[i] 作为循环条件之一 int id=get_id(w[i]/p[k]); // 找到 w[i]/p[k] 即 n'/p[k] 的编号 g1[i]=_sub(g1[i],p[k]*_sub(g1[id],s1[k-1])%TT); // g1[id]-s1[k-1] 即 G_{k-1}(n'/p[k]) - G_prime(p[k-1]) g2[i]=_sub(g2[i],p[k]*p[k]%TT*_sub(g2[id],s2[k-1])%TT); // 同上 } } } int F(int k,int _n){ // 递归计算 F_k(n') if(_n<p[k])return 0; // 若 n' < p[k],则 F_k(n) = 0 int id=get_id(_n); // 找到 n' 的编号 int ret=_sub(_sub(g2[id],g1[id]),_sub(s2[k-1],s1[k-1])); // 即 F_prime(n') - F_prime(p[k-1]) for(int i=k;i<=cnt&&p[i]*p[i]<=_n;i++){ // 枚举质数 p[i] for(int _p=p[i];_p*p[i]<=_n;_p*=p[i]){ // 枚举 p[i] 的次数 c,_p 即 p[i]^c int _p1=_p%TT,_p2=_p1*_p1%TT; int _P1=_p*p[i]%TT,_P2=_P1*_P1%TT; ret=(ret+_sub(_P2,_P1)+_sub(_p2,_p1)*F(i+1,_n/_p)%TT)%TT; // _P2 - _P1 即 f(p[i]^{c+1}),_p2 - _p1 即 f(p[i]^c) } } return ret; } signed main(){ n=read(); b=_sqrt(n); _init(); ans=(F(1,n)+1)%TT; // 答案为 F_1(n) + 1 printf("%lld\n",ans); return 0; } ``` ## 0xFF 参考文献 本文还参考了一篇资料 $^{\textup{\textmd{\textsf{[3]}}}}$。 [1] 朱震霆. 一些特殊的数论函数求和问题[C]//张瑞喆. IOI2018 中国国家候选队论文集. 2018: 92-112. [2] 任之洲. 积性函数求和的几种方法[C]//余林韵, 陈许旻. 2016 年信息学奥林匹克中国国家队候选队员论文集. 2016: 1-16. [3] OI Wiki. Min_25 筛[DB/OL]. (2026-02-08)[2026-03-16]. https://oi-wiki.org/math/number-theory/min-25/. --- **版权声明**:本文中 **0x00**、**0x10**、**0x20** 与 **0x30** 章节参考自 [OI Wiki](https://oi-wiki.org/),其内容在 **[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.zh-hans)** 协议之条款下提供。本文亦采用 **[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.zh-hans)** 协议发布。