Min_25 筛
定义
从此种筛法的思想方法来说,其又被称为「Extended Eratosthenes Sieve」。
由于其由 Min_25 发明并最早开始使用,故称「Min_25 筛」。
性质
其可以在 𝑂(𝑛34log𝑛)
或 Θ(𝑛1−𝜖)
的时间复杂度下解决一类 积性函数 的前缀和问题。
要求:𝑓(𝑝)
是一个关于 𝑝
可以快速求值的完全积性函数之和(例如多项式);𝑓(𝑝𝑐)
可以快速求值。
记号
- 如无特别说明,本节中所有记为 𝑝
的变量的取值集合均为全体质数。 - 𝑥/𝑦 :=⌊𝑥𝑦⌋

- isprime(𝑛) :=[|{𝑑 :𝑑 ∣𝑛}| =2]
,即 𝑛
为质数时其值为 1
,否则为 0
。 - 𝑝𝑘
:全体质数中第 𝑘
小的质数(如:𝑝1 =2,𝑝2 =3
)。特别地,令 𝑝0 =1
。 - lpf(𝑛) :=[1 <𝑛]min{𝑝 :𝑝 ∣𝑛} +[1 =𝑛]
,即 𝑛
的最小质因数。特别地,𝑛 =1
时,其值为 1
。 - 𝐹prime(𝑛) :=∑2≤𝑝≤𝑛𝑓(𝑝)

- 𝐹𝑘(𝑛) :=∑𝑛𝑖=2[𝑝𝑘 ≤lpf(𝑖)]𝑓(𝑖)
![F_{k}(n) := \sum_{i = 2}^{n} [p_{k} \le \operatorname{lpf}(i)] f(i)](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
解释
观察 𝐹𝑘(𝑛)
的定义,可以发现答案即为 𝐹1(𝑛) +𝑓(1) =𝐹1(𝑛) +1
。
考虑如何求出 𝐹𝑘(𝑛)
。通过枚举每个 𝑖
的最小质因子及其次数可以得到递推式:
𝐹𝑘(𝑛)=𝑛∑𝑖=2[𝑝𝑘≤lpf(𝑖)]𝑓(𝑖)=∑𝑘≤𝑖𝑝2𝑖≤𝑛∑𝑐≥1𝑝𝑐𝑖≤𝑛𝑓(𝑝𝑐𝑖)([𝑐>1]+𝐹𝑖+1(𝑛/𝑝𝑐𝑖))+∑𝑘≤𝑖𝑝𝑖≤𝑛𝑓(𝑝𝑖)=∑𝑘≤𝑖𝑝2𝑖≤𝑛∑𝑐≥1𝑝𝑐𝑖≤𝑛𝑓(𝑝𝑐𝑖)([𝑐>1]+𝐹𝑖+1(𝑛/𝑝𝑐𝑖))+𝐹prime(𝑛)−𝐹prime(𝑝𝑘−1)=∑𝑘≤𝑖𝑝2𝑖≤𝑛∑𝑐≥1𝑝𝑐+1𝑖≤𝑛(𝑓(𝑝𝑐𝑖)𝐹𝑖+1(𝑛/𝑝𝑐𝑖)+𝑓(𝑝𝑐+1𝑖))+𝐹prime(𝑛)−𝐹prime(𝑝𝑘−1)![\begin{aligned}
F_{k}(n)
&= \sum_{i = 2}^{n} [p_{k} \le \operatorname{lpf}(i)] f(i) \\
&= \sum_{\substack{k \le i \\ p_{i}^{2} \le n}} \sum_{\substack{c \ge 1 \\ p_{i}^{c} \le n}} f\left(p_{i}^{c}\right) ([c > 1] + F_{i + 1}\left(n / p_{i}^{c}\right)) + \sum_{\substack{k \le i \\ p_{i} \le n}} f(p_{i}) \\
&= \sum_{\substack{k \le i \\ p_{i}^{2} \le n}} \sum_{\substack{c \ge 1 \\ p_{i}^{c} \le n}} f\left(p_{i}^{c}\right) ([c > 1] + F_{i + 1}\left(n / p_{i}^{c}\right)) + F_{\mathrm{prime}}(n) - F_{\mathrm{prime}}(p_{k - 1}) \\
&= \sum_{\substack{k \le i \\ p_{i}^{2} \le n}} \sum_{\substack{c \ge 1 \\ p_{i}^{c + 1} \le n}} \left(f\left(p_{i}^{c}\right) F_{i + 1}\left(n / p_{i}^{c}\right) + f\left(p_{i}^{c + 1}\right)\right) + F_{\mathrm{prime}}(n) - F_{\mathrm{prime}}(p_{k - 1})
\end{aligned}](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
最后一步推导基于这样一个事实:对于满足 𝑝𝑐𝑖 ≤𝑛 <𝑝𝑐+1𝑖
的 𝑐
,有 𝑝𝑐+1𝑖 >𝑛 ⟺ 𝑛/𝑝𝑐𝑖 <𝑝𝑖 <𝑝𝑖+1
,故 𝐹𝑖+1(𝑛/𝑝𝑐𝑖) =0
。
其边界值即为 𝐹𝑘(𝑛) =0(𝑝𝑘 >𝑛)
。
假设现在已经求出了所有的 𝐹prime(𝑛)
,那么有两种方式可以求出所有的 𝐹𝑘(𝑛)
:
- 直接按照递推式计算。
- 从大到小枚举 𝑝
转移,仅当 𝑝2 <𝑛
时转移增加值不为零,故按照递推式后缀和优化即可。
现在考虑如何计算 𝐹prime(𝑛)
。
观察求 𝐹𝑘(𝑛)
的过程,容易发现 𝐹prime
有且仅有 1,2,…,⌊√𝑛⌋,𝑛/√𝑛,…,𝑛/2,𝑛
这 𝑂(√𝑛)
处的点值是有用的。
一般情况下,𝑓(𝑝)
是一个关于 𝑝
的低次多项式,可以表示为 𝑓(𝑝) =∑𝑎𝑖𝑝𝑐𝑖
。
那么对于每个 𝑝𝑐𝑖
,其对 𝐹prime(𝑛)
的贡献即为 𝑎𝑖∑2≤𝑝≤𝑛𝑝𝑐𝑖
。
分开考虑每个 𝑝𝑐𝑖
的贡献,问题就转变为了:给定 𝑛,𝑠,𝑔(𝑝) =𝑝𝑠
,对所有的 𝑚 =𝑛/𝑖
,求 ∑𝑝≤𝑚𝑔(𝑝)
。
注意
𝑔(𝑝) =𝑝𝑠
是完全积性函数!
于是设 𝐺𝑘(𝑛) :=∑𝑛𝑖=2[𝑝𝑘<lpf(𝑖)∨isprime(𝑖)]𝑔(𝑖)
,即埃筛第 𝑘
轮筛完后剩下的数的 𝑔
值之和。
对于一个合数 𝑥 ≤𝑛
,必定有 lpf(𝑥) ≤√𝑥 ≤√𝑛
。设 𝑝ℓ(𝑛)
为不大于 √𝑛
的最大质数,则 ∑2≤𝑝≤𝑛𝑔(𝑝) =𝐺ℓ(𝑛)(𝑛)
,即在埃筛进行 ℓ
轮之后剩下的均为质数。 考虑 𝐺
的边界值,显然为 𝐺0(𝑛) =∑𝑛𝑖=2𝑔(𝑖)
。(还记得吗?特别约定了 𝑝0 =1
)
对于转移,考虑埃筛的过程,分开讨论每部分的贡献,有:
- 对于 𝑛 <𝑝2𝑘
的部分,𝐺
值不变,即 𝐺𝑘(𝑛) =𝐺𝑘−1(𝑛)
。 - 对于 𝑝2𝑘 ≤𝑛
的部分,被筛掉的数必有质因子 𝑝𝑘
,即 −𝑔(𝑝𝑘)𝐺𝑘−1(𝑛/𝑝𝑘)
。 - 对于第二部分,由于 𝑝2𝑘 ≤𝑛 ⟺ 𝑝𝑘 ≤𝑛/𝑝𝑘
,满足 lpf(𝑖) <𝑝𝑘
的 𝑖
会被额外减去。这部分应当加回来,即 𝑔(𝑝𝑘)𝐺𝑘−1(𝑝𝑘−1)
。
则有:
𝐺𝑘(𝑛)=𝐺𝑘−1(𝑛)−[𝑝2𝑘≤𝑛]𝑔(𝑝𝑘)(𝐺𝑘−1(𝑛/𝑝𝑘)−𝐺𝑘−1(𝑝𝑘−1))![G_{k}(n) = G_{k - 1}(n) - \left[p_{k}^{2} \le n\right] g(p_{k}) (G_{k - 1}(n / p_{k}) - G_{k - 1}(p_{k - 1}))](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
复杂度分析
对于 𝐹𝑘(𝑛)
的计算,其第一种方法的时间复杂度被证明为 𝑂(𝑛1−𝜖)
(见 zzt 集训队论文 2.3);
对于第二种方法,其本质即为洲阁筛的第二部分,在洲阁论文中也有提及(6.5.4),其时间复杂度被证明为 𝑂(𝑛34log𝑛)
。
对于 𝐹prime(𝑛)
的计算,事实上,其实现与洲阁筛第一部分是相同的。
考虑对于每个 𝑚 =𝑛/𝑖
,只有在枚举满足 𝑝2𝑘 ≤𝑚
的 𝑝𝑘
转移时会对时间复杂度产生贡献,则时间复杂度可估计为:
𝑇(𝑛)=∑𝑖2≤𝑛𝑂(𝜋(√𝑖))+∑𝑖2≤𝑛𝑂(𝜋(√𝑛𝑖))=∑𝑖2≤𝑛𝑂(√𝑖ln√𝑖)+∑𝑖2≤𝑛𝑂(√𝑛𝑖ln√𝑛𝑖)=𝑂(∫√𝑛1√𝑛𝑥log√𝑛𝑥d𝑥)=𝑂(𝑛34log𝑛)
对于空间复杂度,可以发现不论是 𝐹𝑘
还是 𝐹prime
,其均只在 𝑛/𝑖
处取有效点值,共 𝑂(√𝑛)
个,仅记录有效值即可将空间复杂度优化至 𝑂(√𝑛)
。
首先,通过一次数论分块可以得到所有的有效值,用一个大小为 𝑂(√𝑛)
的数组 lis
记录。对于有效值 𝑣
,记 id(𝑣)
为 𝑣
在 lis
中的下标,易得:对于所有有效值 𝑣
,id(𝑣) ≤√𝑛
。
然后分开考虑小于等于 √𝑛
的有效值和大于 √𝑛
的有效值:对于小于等于 √𝑛
的有效值 𝑣
,用一个数组 le
记录其 id(𝑣)
,即 le𝑣 =id(𝑣)
;对于大于 √𝑛
的有效值 𝑣
,用一个数组 ge
记录 id(𝑣)
,由于 𝑣
过大所以借助 𝑣′ =𝑛/𝑣 <√𝑛
记录 id(𝑣)
,即 ge𝑣′ =id(𝑣)
。
这样,就可以使用两个大小为 𝑂(√𝑛)
的数组记录所有有效值的 id
并 𝑂(1)
查询。在计算 𝐹𝑘
或 𝐹prime
时,使用有效值的 id
代替有效值作为下标,即可将空间复杂度优化至 𝑂(√𝑛)
。
过程
对于 𝐹𝑘(𝑛)
的计算,我们实现时一般选择实现难度较低的第一种方法,其在数据规模较小时往往比第二种方法的表现要好;
对于 𝐹prime(𝑛)
的计算,直接按递推式实现即可。
对于 𝑝2𝑘 ≤𝑛
,可以用线性筛预处理出 𝑠𝑘 :=𝐹prime(𝑝𝑘)
来替代 𝐹𝑘
递推式中的 𝐹prime(𝑝𝑘−1)
。
相应地,𝐺
递推式中的 𝐺𝑘−1(𝑝𝑘−1) =∑𝑘−1𝑖=1𝑔(𝑝𝑖)
也可以用此方法预处理。
用 Extended Eratosthenes Sieve 求 积性函数 𝑓
的前缀和时,应当明确以下几点:
- 如何快速(一般是线性时间复杂度)筛出前 √𝑛
个 𝑓
值; - 𝑓(𝑝)
的多项式表示; - 如何快速求出 𝑓(𝑝𝑐)
。
明确上述几点之后按顺序实现以下几部分即可:
- 筛出 [1,√𝑛]
内的质数与前 √𝑛
个 𝑓
值; - 对 𝑓(𝑝)
多项式表示中的每一项筛出对应的 𝐺
,合并得到 𝐹prime
的所有 𝑂(√𝑛)
个有用点值; - 按照 𝐹𝑘
的递推式实现递归,求出 𝐹1(𝑛)
。
例题
Luogu P4213【模板】杜教筛
求 𝑛∑𝑖=1𝜑(𝑖)
和 𝑛∑𝑖=1𝜇(𝑖)
。
解答
对于求 𝜑(𝑖)
的前缀和,首先易知 𝑓(𝑝) =𝑝 −1
。对于 𝑓(𝑝)
的一次项 (𝑝)
,有 𝑔(𝑝) =𝑝,𝐺0(𝑛) =∑𝑛𝑖=2𝑔(𝑖) =(𝑛+2)(𝑛−1)2
;对于 𝑓(𝑝)
的常数项 ( −1)
,有 𝑔(𝑝) = −1,𝐺0(𝑛) =∑𝑛𝑖=2𝑔(𝑖) = −𝑛 +1
。筛两次加起来即可得到 𝐹prime
的所有 𝑂(√𝑛)
个所需点值。
对于求 𝜇(𝑖)
的前缀和,易知 𝑓(𝑝) = −1
。则 𝑔(𝑝) = −1,𝐺0(𝑛) =∑𝑛𝑖=2𝑔(𝑖) = −𝑛 +1
。直接筛即可得到 𝐹prime
的所有 𝑂(√𝑛)
个所需点值。
LOJ 6053 简单的函数
给定 𝑓(𝑛)
:
𝑓(𝑛)=⎧{ {⎨{ {⎩1𝑛=1𝑝xor𝑐𝑛=𝑝𝑐𝑓(𝑎)𝑓(𝑏)𝑛=𝑎𝑏∧𝑎⟂𝑏
求 𝑛∑𝑖=1𝑓(𝑖)
。
解答
易知 𝑓(𝑝) =𝑝 −1 +2[𝑝 =2]
。则按照筛 𝜑
的方法筛,对 2
讨论一下即可。
参考代码
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 | /* 「LOJ #6053」简单的函数 */
#include <cmath>
#include <iostream>
constexpr int MAXS = 200000; // 2sqrt(n)
constexpr int mod = 1000000007;
template <typename x_t, typename y_t>
void inc(x_t &x, const y_t &y) {
x += y;
(mod <= x) && (x -= mod);
}
template <typename x_t, typename y_t>
void dec(x_t &x, const y_t &y) {
x -= y;
(x < 0) && (x += mod);
}
template <typename x_t, typename y_t>
int sum(const x_t &x, const y_t &y) {
return x + y < mod ? x + y : (x + y - mod);
}
template <typename x_t, typename y_t>
int sub(const x_t &x, const y_t &y) {
return x < y ? x - y + mod : (x - y);
}
template <typename _Tp>
int div2(const _Tp &x) {
return ((x & 1) ? x + mod : x) >> 1;
}
// 以上目的均为防负数和取模
template <typename _Tp>
long long sqrll(const _Tp &x) { // 平方函数
return (long long)x * x;
}
int pri[MAXS / 7], lpf[MAXS + 1], spri[MAXS + 1], pcnt;
void sieve(const int &n) {
for (int i = 2; i <= n; ++i) {
if (lpf[i] == 0) { // 记录质数
lpf[i] = ++pcnt;
pri[lpf[i]] = i;
spri[pcnt] = sum(spri[pcnt - 1], i); // 前缀和
}
for (int j = 1, v; j <= lpf[i] && (v = i * pri[j]) <= n; ++j) lpf[v] = j;
}
}
long long global_n;
int lim;
int le[MAXS + 1], // x <= \sqrt{n}
ge[MAXS + 1]; // x > \sqrt{n}
#define idx(v) (v <= lim ? le[v] : ge[global_n / v])
int G[MAXS + 1][2], Fprime[MAXS + 1];
long long lis[MAXS + 1];
int cnt;
void init(const long long &n) {
for (long long i = 1, j, v; i <= n; i = n / j + 1) {
j = n / i;
v = j % mod;
lis[++cnt] = j;
(j <= lim ? le[j] : ge[global_n / j]) = cnt;
G[cnt][0] = sub(v, 1ll);
G[cnt][1] = div2((long long)(v + 2ll) * (v - 1ll) % mod);
}
}
void calcFprime() {
for (int k = 1; k <= pcnt; ++k) {
const int p = pri[k];
const long long sqrp = sqrll(p);
for (int i = 1; lis[i] >= sqrp; ++i) {
const long long v = lis[i] / p;
const int id = idx(v);
dec(G[i][0], sub(G[id][0], k - 1));
dec(G[i][1], (long long)p * sub(G[id][1], spri[k - 1]) % mod);
}
}
/* F_prime = G_1 - G_0 */
for (int i = 1; i <= cnt; ++i) Fprime[i] = sub(G[i][1], G[i][0]);
}
int f_p(const int &p, const int &c) {
/* f(p^{c}) = p xor c */
return p ^ c;
}
int F(const int &k, const long long &n) {
if (n < pri[k] || n <= 1) return 0;
const int id = idx(n);
long long ans = Fprime[id] - (spri[k - 1] - (k - 1));
if (k == 1) ans += 2;
for (int i = k; i <= pcnt && sqrll(pri[i]) <= n; ++i) {
long long pw = pri[i], pw2 = sqrll(pw);
for (int c = 1; pw2 <= n; ++c, pw = pw2, pw2 *= pri[i])
ans +=
((long long)f_p(pri[i], c) * F(i + 1, n / pw) + f_p(pri[i], c + 1)) %
mod;
}
return ans % mod;
}
using std::cin;
using std::cout;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
cin >> global_n;
lim = sqrt(global_n); // 上限
sieve(lim + 1000); // 预处理
init(global_n);
calcFprime();
cout << (F(1, global_n) + 1ll + mod) % mod << '\n';
return 0;
}
|
本页面最近更新:2025/9/22 01:44:35,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:Marcythm, Tiphereth-A, Xeonacid, MegaOwIer, StudyingFather, CSPNOIP, Enter-tainer, aofall, Backl1ght, c-forrest, CoelacanthusHex, Great-designer, Haohu Shen, HeRaNO, iamtwz, Ir1d, kenlig, Konano, ksyx, Persdre, Revltalize, SamZhangQingChuan, shuzhouliu, ZnPdCo
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用