知识点 - 杜教筛
解决问题类型:
积性函数前缀和,
做法是 将原函数和恒等函数卷积得到F,对F求前缀和并使用微扰法求出原函数前缀和。
模板:
//注意mp<int,ll>
//一般很卡常,可以考虑换语言交
ll GetSum(int n) { // 算 f 前缀和的函数
ll ans = f_g_sum(n); // 算 f * g 的前缀和
// 以下这个 for 循环是整除分块
for(ll l = 2, r; l <= n; l = r + 1) { // 注意从 2 开始
r = (n / (n / l));
ans -= (g_sum(r) - g_sum(l - 1)) * GetSum(n / l);
// g_sum 是 g 的前缀和
// 递归 GetSum 求解
} return ans;
}
公式推导:
问题:设f(n)为数论函数,求
S
(
n
)
=
∑
i
=
1
n
f
(
n
)
S(n)=\sum_{i=1}^{n} f(n)
S(n)=i=1∑nf(n)
想法:根据
f
(
n
)
f(n)
f(n)的性质,构造一个
S
(
n
)
S(n)
S(n)关于
S
(
⌊
n
i
⌋
)
S(\lfloor \frac{n}{i}\rfloor)
S(⌊in⌋)的递推式。
构造方法如下:
找到一个合适的
g
(
n
)
,
l
e
t
F
=
f
∗
g
g(n)\ , \mathrm{let}\ F=f*g
g(n) ,let F=f∗g 即
F
(
n
)
=
∑
d
∣
n
f
(
n
d
)
g
(
d
)
F(n)=\sum_{d|n}f(\frac{n}{d})g(d)
F(n)=d∣n∑f(dn)g(d)
对F求前缀和,则有
∑
F
(
n
)
=
∑
i
=
1
n
∑
d
∣
i
f
(
i
d
)
g
(
d
)
=
∑
d
∣
i
∑
d
=
1
n
f
(
i
d
)
g
(
d
)
=
∑
d
=
1
n
g
(
d
)
∑
i
=
1
⌊
n
d
⌋
f
(
i
)
=
∑
d
=
1
n
g
(
d
)
S
(
⌊
n
d
⌋
)
\sum F(n)=\sum_{i=1}^{n}\sum_{d|i}f(\frac{i}{d})g(d)=\sum_{d|i}\sum_{d=1}^nf(\frac{i}{d})g(d)\\ =\sum_{d=1}^ng(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} f(i)=\sum_{d=1}^{n}g(d)S(\lfloor\frac{n}{d}\rfloor)
∑F(n)=i=1∑nd∣i∑f(di)g(d)=d∣i∑d=1∑nf(di)g(d)=d=1∑ng(d)i=1∑⌊dn⌋f(i)=d=1∑ng(d)S(⌊dn⌋)
即
∑
i
=
1
n
∑
d
∣
i
f
(
d
)
g
(
i
d
)
=
∑
i
=
1
n
g
(
i
)
S
(
⌊
n
i
⌋
)
\sum_{i=1}^{n}\sum_{d|i}f(d)g(\frac{i}{d})=\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)\\
i=1∑nd∣i∑f(d)g(di)=i=1∑ng(i)S(⌊in⌋)
提出
g
(
1
)
S
(
n
)
g(1)S(n)
g(1)S(n),移项(即微扰法 perturb the sum)可以得到递推式
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
F
(
i
)
−
∑
i
=
2
n
g
(
i
)
S
(
⌊
n
i
⌋
)
g(1)S(n)=\sum_{i=1}^{n}F(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)
g(1)S(n)=i=1∑nF(i)−i=2∑ng(i)S(⌊in⌋)
注意到后半部分的式子中的
S
(
⌊
n
i
⌋
)
S(\lfloor\frac{n}{i}\rfloor)
S(⌊in⌋)可以用整除分块
O
(
n
)
O(\sqrt n)
O(n)地求出(见知识点 - 整除分块)。
复杂度
若能够快速求:(具体来说,小于
O
(
n
)
O(\sqrt{n})
O(n))
∑
i
=
1
n
(
f
∗
g
)
(
i
)
,
∑
i
=
1
n
g
(
i
)
\sum_{i=1}^{n}(f*g)(i),\sum_{i=1}^{n}g(i)
i=1∑n(f∗g)(i),i=1∑ng(i)
那么计算单个S(n)的时间复杂度就变为
T
(
n
)
=
O
(
n
)
+
∑
i
=
1
n
(
T
(
i
)
+
T
(
n
i
)
)
T(n)=O(\sqrt{n})+\sum_{i=1}^{\sqrt{n}}{(T(i)+T(\frac{n}{i}))}\\\ \\
T(n)=O(n)+i=1∑n(T(i)+T(in))
展开一阶小量,积分,有
T
(
n
)
=
∑
i
=
1
n
O
(
i
)
+
O
(
n
i
)
=
O
(
n
3
4
)
T(n)=\sum_{i=1}^{\sqrt{n}}{O(\sqrt{i})+O(\sqrt{\frac{n}{i}})}=O(n^\frac{3}{4})
T(n)=i=1∑nO(i)+O(in)=O(n43)
可以打表预处理来加速,如果线性预处理出了f(n)的前k项
(
k
≥
n
)
(k\ge\sqrt{n})
(k≥n),此时复杂度变为:
T
(
n
)
=
k
+
∑
i
=
1
n
k
n
i
=
O
(
n
k
+
k
)
T(n)=k+\sum_{i=1}^{\frac{n}{k}}{\sqrt{\frac{n}{i}}}=O(\frac{n}{\sqrt{k}}+k)
T(n)=k+i=1∑knin=O(kn+k)
k
=
n
2
3
k=n^\frac{2}{3}
k=n32时取到最小值
O
(
2
n
2
3
)
O(2n^\frac{2}{3})
O(2n32)
例题1
令 Φ ( n ) = ∑ i = 1 n φ ( i ) \Phi(n)=\sum_{i=1}^{n}{\varphi(i)} Φ(n)=∑i=1nφ(i)为欧拉函数前缀和。
解析
利用性质
∑
d
∣
n
φ
(
d
)
=
n
⇔
I
∗
φ
=
i
d
\sum_{d|n}{\varphi(d)}=n\Leftrightarrow I*\varphi=id
d∣n∑φ(d)=n⇔I∗φ=id
所以令
g
(
n
)
g(n)
g(n)为常函数
I
(
n
)
=
1
I(n)=1
I(n)=1,带入通式
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
F
(
i
)
−
∑
i
=
2
n
g
(
i
)
S
(
⌊
n
i
⌋
)
g(1)S(n)=\sum_{i=1}^{n}F(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)\\
g(1)S(n)=i=1∑nF(i)−i=2∑ng(i)S(⌊in⌋)
得到:
1
⋅
Φ
(
n
)
=
∑
i
=
1
n
i
−
∑
i
=
2
n
1
⋅
Φ
(
⌊
n
i
⌋
)
1\cdot \Phi(n)=\sum_{i=1}^{n}i-\sum_{i=2}^{n}1\cdot \Phi(\lfloor\frac{n}{i}\rfloor)\\
1⋅Φ(n)=i=1∑ni−i=2∑n1⋅Φ(⌊in⌋)
(补充推导:当然也可以从
I
∗
φ
=
i
d
I*\varphi=id
I∗φ=id直接从头推导,有
∴
φ
(
n
)
=
n
−
∑
d
∣
n
,
d
<
n
φ
(
d
)
\therefore \varphi(n)=n-\sum_{d|n,d<n}{\varphi(d)}
∴φ(n)=n−d∣n,d<n∑φ(d)
推导得:
ϕ
(
n
)
=
∑
i
=
1
n
φ
(
i
)
=
∑
i
=
1
n
i
−
∑
d
∣
i
,
d
<
i
φ
(
d
)
=
n
⋅
(
n
+
1
)
2
−
∑
i
=
2
n
∑
d
∣
i
,
d
<
i
φ
(
d
)
=
n
⋅
(
n
+
1
)
2
−
∑
i
d
=
2
n
∑
d
=
1
⌊
n
i
d
⌋
φ
(
d
)
=
n
⋅
(
n
+
1
)
2
−
∑
i
=
2
n
∑
d
=
1
⌊
n
i
⌋
φ
(
d
)
=
n
⋅
(
n
+
1
)
2
−
∑
i
=
2
n
ϕ
(
⌊
n
i
⌋
)
\phi(n)=\sum_{i=1}^{n}{\varphi(i)}=\sum_{i=1}^{n}{i-\sum_{d|i,d<i}{\varphi(d)}}=\frac{n\cdot(n+1)}{2}-\sum_{i=2}^{n}\sum_{d|i,d<i}{\varphi(d)}=\frac{n\cdot(n+1)}{2}-\sum_{\frac{i}{d}=2}^{n}\sum_{d=1}^{\left\lfloor\frac{n}{\frac{i}{d}}\right\rfloor}{\varphi(d)}\\=\frac{n\cdot(n+1)}{2}-\sum_{i=2}^{n}\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}{\varphi(d)}=\frac{n\cdot(n+1)}{2}-\sum_{i=2}^{n}{\phi(\lfloor\frac{n}{i}\rfloor)}
ϕ(n)=i=1∑nφ(i)=i=1∑ni−d∣i,d<i∑φ(d)=2n⋅(n+1)−i=2∑nd∣i,d<i∑φ(d)=2n⋅(n+1)−di=2∑nd=1∑⌊din⌋φ(d)=2n⋅(n+1)−i=2∑nd=1∑⌊in⌋φ(d)=2n⋅(n+1)−i=2∑nϕ(⌊in⌋)
)
理论分析
具体数学4.9节的做法:
首先对于实数x有结论:
∑
d
≥
1
Φ
(
x
d
)
=
⌊
x
⌋
⋅
⌊
x
+
1
⌋
/
2
w
h
e
r
e
Φ
(
x
)
=
Φ
(
⌊
x
⌋
)
\sum_{d\ge1}\Phi(\frac{x}{d})=\lfloor x\rfloor\cdot\lfloor x+1\rfloor/2\\ \mathrm{where\ }\Phi(x)=\Phi(\lfloor x\rfloor)
d≥1∑Φ(dx)=⌊x⌋⋅⌊x+1⌋/2where Φ(x)=Φ(⌊x⌋)
(微扰法将第1项提出来有
Φ
(
x
)
=
⌊
x
⌋
⋅
⌊
x
+
1
⌋
/
2
−
∑
d
≥
2
Φ
(
⌊
x
d
⌋
)
\Phi(x)=\lfloor x\rfloor\cdot\lfloor x+1\rfloor/2-\sum_{d\ge2}\Phi(\lfloor \frac{x}{d}\rfloor)
Φ(x)=⌊x⌋⋅⌊x+1⌋/2−d≥2∑Φ(⌊dx⌋)
得到杜教筛的递推式。)
第一个式子可以这么理解:可以将右边看成所有 0 ≤ m < n ≤ x 0\le m\lt n\le x 0≤m<n≤x的分数 m n \frac{m}{n} nm的(未约分)分数的数量,而左边可以理解为形式为 m n \frac{m}{n} nm且 g c d ( m , n ) = d \mathrm{gcd}(m,n)=d gcd(m,n)=d的分数的个数为 Φ ( x d ) \Phi(\frac{x}{d}) Φ(dx).
精确推导如下:
n
⋅
(
n
+
1
)
2
=
∑
i
=
1
n
i
=
∑
i
=
1
n
∑
d
[
d
∣
i
]
⋅
φ
(
d
)
=
∑
i
d
=
1
n
∑
d
=
1
⌊
n
i
d
⌋
φ
(
d
)
=
∑
i
=
1
n
ϕ
(
⌊
n
i
⌋
)
\frac{n\cdot(n+1)}{2}=\sum_{i=1}^{n}{i}=\sum_{i=1}^{n}\sum_{d}{[d|i]\cdot\varphi(d)}=\sum_{\frac{i}{d}=1}^{n}\sum_{d=1}^{\left\lfloor\frac{n}{\frac{i}{d}}\right\rfloor}{\varphi(d)}=\sum_{i=1}^{n}{\phi(\lfloor\frac{n}{i}\rfloor)}
2n⋅(n+1)=i=1∑ni=i=1∑nd∑[d∣i]⋅φ(d)=di=1∑nd=1∑⌊din⌋φ(d)=i=1∑nϕ(⌊in⌋)
直接对第一个式子使用莫比乌斯反演变式:
g
(
x
)
=
∑
d
≥
1
f
(
x
/
d
)
⇔
f
(
x
)
=
∑
d
≥
1
μ
(
d
)
g
(
x
/
d
)
g(x)=\sum_{d\ge1}f(x/d)\Leftrightarrow f(x)=\sum_{d\ge1}\mu(d)g(x/d)
g(x)=d≥1∑f(x/d)⇔f(x)=d≥1∑μ(d)g(x/d)
注意这个变式与原莫比乌斯公式的区别:
g
(
n
)
=
∑
d
∣
n
f
(
d
)
⇔
f
(
n
)
=
∑
d
∣
n
g
(
n
d
)
μ
(
d
)
g(n)=\sum_{d|n}f(d)\Leftrightarrow f(n)=\sum_{d|n}g(\frac{n}{d})\mu(d)
g(n)=d∣n∑f(d)⇔f(n)=d∣n∑g(dn)μ(d)
该变式适用于所有
∑
k
,
d
≥
1
∣
f
(
x
/
k
d
)
∣
<
∞
\sum_{k,d\ge1}|f(x/kd)|\lt \infty
k,d≥1∑∣f(x/kd)∣<∞
这里顺便证明一下:
∑
d
≥
1
μ
(
d
)
g
(
x
/
d
)
=
∑
d
≥
1
μ
(
d
)
∑
k
≥
1
f
(
x
/
k
d
)
=
∑
m
≥
1
f
(
x
/
m
)
∑
k
,
d
≥
1
μ
(
d
)
[
m
=
k
d
]
=
∑
m
≥
1
f
(
x
/
m
)
∑
d
∣
m
μ
(
d
)
=
∑
m
≥
1
f
(
x
/
m
)
[
m
=
1
]
=
f
(
x
)
\sum_{d\ge1}\mu(d)g(x/d)=\sum_{d\ge1}\mu(d)\sum_{k\ge1}f(x/kd)\\\ \\ =\sum_{m\ge1}f(x/m)\sum_{k,d\ge1}\mu(d)[m=kd]\\\ \\ =\sum_{m\ge1}f(x/m)\sum_{d|m}\mu(d)=\sum_{m\ge1}f(x/m)[m=1]=f(x)
d≥1∑μ(d)g(x/d)=d≥1∑μ(d)k≥1∑f(x/kd) =m≥1∑f(x/m)k,d≥1∑μ(d)[m=kd] =m≥1∑f(x/m)d∣m∑μ(d)=m≥1∑f(x/m)[m=1]=f(x)
∑
d
≥
1
Φ
(
x
d
)
\sum_{d\ge1}\Phi(\frac{x}{d})
∑d≥1Φ(dx)用反演,得到
Φ
(
x
)
=
1
/
2
∑
d
≥
1
μ
(
d
)
⌊
x
/
d
⌋
⋅
⌊
x
/
d
+
1
⌋
\Phi(x)=1/2\sum_{d\ge1}\mu(d)\lfloor x/d\rfloor\cdot\lfloor x/d+1\rfloor\\
Φ(x)=1/2d≥1∑μ(d)⌊x/d⌋⋅⌊x/d+1⌋
由于
⌊
x
/
d
⌋
\lfloor x/d\rfloor
⌊x/d⌋前有莫比乌斯函数的系数,无法用整除分块,复杂度依然为O(n)。
不过这个式子可以用来计算近似值:(具体数学ch9中有证明)
Φ
(
x
)
=
3
/
π
2
x
2
+
O
(
x
l
o
g
x
)
\Phi(x)=3/\pi^2x^2+O(xlogx)
Φ(x)=3/π2x2+O(xlogx)
例题2
求梅滕斯函数 M ( n ) = ∑ i = 1 n μ ( i ) M(n)=\sum_{i=1}^{n}{\mu(i)} M(n)=∑i=1nμ(i)
解析
利用性质
[
n
=
1
]
=
∑
d
∣
n
μ
(
d
)
n
⇔
I
∗
μ
=
e
[n=1]=\sum_{d|n}{\mu(d)} n\Leftrightarrow I*\mu=e
[n=1]=d∣n∑μ(d)n⇔I∗μ=e
和上一题同样地,令
g
(
n
)
g(n)
g(n)为常函数
I
(
n
)
=
1
I(n)=1
I(n)=1,带入通式
g
(
1
)
S
(
n
)
=
∑
i
=
1
n
F
(
i
)
−
∑
i
=
2
n
g
(
i
)
S
(
⌊
n
i
⌋
)
g(1)S(n)=\sum_{i=1}^{n}F(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)\\
g(1)S(n)=i=1∑nF(i)−i=2∑ng(i)S(⌊in⌋)
得到
1
⋅
M
(
n
)
=
1
−
∑
i
=
2
n
1
⋅
M
(
⌊
n
i
⌋
)
1\cdot \Mu(n)=1-\sum_{i=2}^{n}1\cdot \Mu(\lfloor\frac{n}{i}\rfloor)\\
1⋅M(n)=1−i=2∑n1⋅M(⌊in⌋)
(补充推导:
1
=
∑
i
=
1
n
[
i
=
1
]
=
∑
i
=
1
n
∑
d
∣
i
μ
(
d
)
=
∑
i
=
1
n
∑
d
=
1
⌊
n
i
⌋
μ
(
d
)
=
∑
i
=
1
n
M
(
⌊
n
i
⌋
)
1=\sum_{i=1}^{n}{[i=1]}=\sum_{i=1}^{n}\sum_{d|i}{\mu(d)}=\sum_{i=1}^{n}\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}{\mu(d)}=\sum_{i=1}^{n}{M(\lfloor\frac{n}{i}\rfloor)}
1=i=1∑n[i=1]=i=1∑nd∣i∑μ(d)=i=1∑nd=1∑⌊in⌋μ(d)=i=1∑nM(⌊in⌋)
)
代码:
#include<iostream>
#include<map>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<set>
#include<sstream>
#include<cstdio>
#include<cmath>
#include<climits>
#include<cstdlib>
#include<iomanip>
#include<unordered_map>
using namespace std;
const double PI = acos(-1.0);
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define debug(x) cerr<<#x<<":"<<x<<endl
#define pb push_back
#define FAST_IO ios::sync_with_stdio(0); cin.tie(0)
const int maxn = 1e7;
const int N = 3e6;
typedef long long ll;
int mu[N], lp[N], sumu[N];
ll phi[N],sump[N];
vector<int> pr;
void init() {
mu[1] = 1;
phi[1] = 1;
for (int i = 2; i <= N; ++i) {
if (lp[i] == 0) {
lp[i] = i;
mu[i] = -1;
phi[i] = i - 1;
pr.push_back(i);
}
for (int j = 0; j < (int)pr.size() && pr[j] <= lp[i] && i*pr[j] <= N; ++j)
{
lp[i * pr[j]] = pr[j];
if (i%pr[j])phi[i*pr[j]] = phi[i] * (pr[j] - 1), mu[i * pr[j]] = -mu[i];
else phi[i*pr[j]] = phi[i] * pr[j];
}
}
sumu[0] = 0;
sump[0] = 0;
rep(i, 1, N-1) {
sumu[i] = sumu[i-1] + mu[i];
sump[i] = sump[i - 1] + phi[i];
}
}
unordered_map<int,ll> Smu, Sphi;
inline ll GetSumu(int n) {
if (n <= N-1) return sumu[n]; // sumu是提前筛好的前缀和
if (Smu[n]) return Smu[n]; // 记忆化
ll ret = 1ll; // 单位元的前缀和就是 1
for (int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l); ret -= (r - l + 1) * GetSumu(n / l);
// (r - l + 1) 就是 I 在 [l, r] 的和
} return Smu[n] = ret; // 记忆化
}
inline ll GetSphi(int n) {
if (n <= N-1) return sump[n]; // 提前筛好的
if (Sphi[n]) return Sphi[n]; // 记忆化
ll ret = 1ll * n * (n + 1) / 2; // f * g = id 的前缀和
for (int l = 2, r; l <= n; l = r + 1) {
r = n / (n / l); ret -= (r - l + 1) * GetSphi(n / l);
// 同上,因为两个的 g 都是 I
} return Sphi[n] = ret; // 记忆化
}
int main() {
init();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
cout << GetSphi(n) << ' ' << GetSumu(n) << endl;
}
int n;
cin >> n;
}
/*
6
1
2
8
13
30
2333
*/