欧拉筛法
众所周知欧拉筛法一般用于在线性时间内筛选出 1~n 范围内的质数,但是在数论问题中欧拉筛法的用途不仅仅是筛素数,它还可以干其他三件事,只不过这些问题被提及的次数比较少。
欧拉筛法可以干哪些事呢?
- 求 1~n 之间所有质数
- 求 1~n 之间所有自然数的欧拉函数 φ(x)
- 求 1~n 之间每个数的因子个数
- 求 1~n 之间每个数的因数和
1. 筛质数
这个大家应该很熟悉了,这里就写一个关键点吧。
欧拉筛法核心思想:每个合数只被自己的最小质因子筛一次。
对 i%prime[j]==0 时即跳出循环的解释:此时可以令 i = k×prime[j],若不跳出,继续筛 i×prime[j+1] 的话,i×prime[j+1] = k×prime[j]×prime[j+1],它的最小质因子显然是 prime[j] 而不是 prime[j+1],违反了筛法原则。
2. 欧拉函数
欧拉函数 φ(x) 表示小于x的,与 x 互质的数的个数。
积性函数
积性函数指对任意互质的整数 a和b,都有 f(a×b) = f(a)×f(b) 的数论函数
当对任意的整数 a,b 都有 f(a×b) = f(a)×f(b) 时,称 f 为完全积性函数。
欧拉函数是积性函数,但不是完全积性函数。
欧拉函数公式:
ϕ
(
x
)
=
x
×
∏
i
=
1
n
(
1
−
1
P
i
)
\phi(x) = x\times\prod_{i=1}^n(1-\frac{1}{Pi})
ϕ(x)=x×i=1∏n(1−Pi1)
其中P1,P2…Pn 是 x 的质因子。
质因数分解
根据唯一分解定理,每一个大于等于2的正整数 n 都有:
n
=
P
1
ω
1
×
P
2
ω
2
×
⋅
⋅
⋅
P
m
ω
m
n=P1^{\omega1} \times P2^{\omega2} \times \cdot\cdot\cdot Pm^{\omega m}
n=P1ω1×P2ω2×⋅⋅⋅Pmωm
由于质数间互质,所以
P
i
ω
i
Pi^{\omega i}
Piωi 和
P
j
ω
j
Pj^{\omega j}
Pjωj 互质。所以根据欧拉函数的积性:
ϕ
(
n
)
=
ϕ
(
P
1
ω
1
×
P
2
ω
2
×
⋅
⋅
⋅
×
P
m
ω
m
)
=
ϕ
(
P
1
ω
1
)
×
ϕ
(
P
2
ω
2
)
×
⋅
⋅
⋅
×
ϕ
(
P
m
ω
m
)
\phi(n) = \phi(P1^{\omega1} \times P2^{\omega2} \times \cdot\cdot\cdot \times Pm^{\omega m}) \\= \phi(P1^{\omega1}) \times \phi(P2^{\omega2}) \times \cdot\cdot\cdot \times \phi(Pm^{\omega m})
ϕ(n)=ϕ(P1ω1×P2ω2×⋅⋅⋅×Pmωm)=ϕ(P1ω1)×ϕ(P2ω2)×⋅⋅⋅×ϕ(Pmωm)
这个记为(1)式。
欧拉函数还有两个性质:
- 当p是质数时, ϕ ( p ) = p − 1 \phi(p) = p-1 ϕ(p)=p−1
- ϕ ( p k ) = p k − p k − 1 = p k − 1 × ( p − 1 ) \phi(p^k) = p^k-p^{k-1}=p^{k-1} \times (p-1) ϕ(pk)=pk−pk−1=pk−1×(p−1)
对性质二的解释:只有一个数的因子不含质数 p 时,才有可能与
p
k
p^k
pk 互质。而小于等于
p
k
p^k
pk 的数中因子包含 p 的数有
p
k
−
1
p^{k-1}
pk−1 个,即
1
×
p
1 \times p
1×p,
2
×
p
2 \times p
2×p,
⋅
⋅
⋅
\cdot\cdot\cdot
⋅⋅⋅,
p
k
−
1
×
p
p^{k-1} \times p
pk−1×p。从总数
p
k
p^k
pk 中把他们去除便剩下了与
p
k
p^k
pk 互质的数。
所以由 (1) 式,可以的到
ϕ
(
x
)
\phi(x)
ϕ(x) 的另一个公式。
ϕ
(
x
)
=
∏
i
=
1
m
P
i
ω
i
−
1
×
(
P
i
−
1
)
\phi(x)=\prod_{i=1}^mPi^{\omega i-1} \times(Pi-1)
ϕ(x)=i=1∏mPiωi−1×(Pi−1)
利用欧拉筛法求欧拉函数
分两种情况讨论:
当 i%prime[j] == 0 时,由于之前说明了 prime[j] 是 i×prime[j] 的最小质因子,所以 i×prime[j] 仅比 i 多一个最小质因子 prime[j],即 P1。
ϕ
(
i
×
p
r
i
m
e
[
j
]
)
=
P
1
ω
1
−
1
+
1
×
(
P
1
−
1
)
×
P
2
ω
2
−
1
×
(
P
2
−
1
)
×
⋅
⋅
⋅
×
P
m
ω
m
−
1
×
(
P
m
−
1
)
=
ϕ
(
i
)
×
P
1
=
ϕ
(
i
)
×
p
r
i
m
e
[
j
]
\phi(i \times prime[j])=P_1^{\omega_1-1+1} \times (P_1-1) \times P_2^{\omega_2-1} \times (P_2-1) \times \cdot\cdot\cdot \times P_m^{\omega_m-1} \times (P_m-1)\\=\phi(i) \times P_1 = \phi(i) \times prime[j]
ϕ(i×prime[j])=P1ω1−1+1×(P1−1)×P2ω2−1×(P2−1)×⋅⋅⋅×Pmωm−1×(Pm−1)=ϕ(i)×P1=ϕ(i)×prime[j]
当 i % prime[j] != 0 时,易知此时 i 与 prime[j] 互质,根据积性性质:
ϕ
(
i
×
p
r
i
m
e
[
j
]
)
=
ϕ
(
i
)
×
ϕ
(
p
r
i
m
e
[
j
]
)
=
ϕ
(
i
)
×
(
p
r
i
m
e
[
j
]
−
1
)
\phi(i \times prime[j])=\phi(i) \times \phi(prime[j])\\= \phi(i) \times (prime[j]-1)
ϕ(i×prime[j])=ϕ(i)×ϕ(prime[j])=ϕ(i)×(prime[j]−1)
3. 欧拉筛法求1~n每个数的约数个数
我们用
d
(
x
)
d(x)
d(x) 表示约数个数。
由于:
n
=
P
1
ω
1
×
P
2
ω
2
×
⋅
⋅
⋅
P
m
ω
m
n=P1^{\omega1} \times P2^{\omega2} \times \cdot\cdot\cdot Pm^{\omega m}
n=P1ω1×P2ω2×⋅⋅⋅Pmωm ,考虑 n 的因数的因式分解:
ω
1
\omega1
ω1可以有 0,1,2 …
ω
1
\omega1
ω1,共
ω
1
+
1
\omega1+1
ω1+1 种选择。同理,
ω
2
\omega2
ω2,
ω
3
\omega3
ω3
⋅
⋅
⋅
\cdot\cdot\cdot
⋅⋅⋅ 都有
ω
2
+
1
\omega2+1
ω2+1,
ω
3
+
1
\omega3+1
ω3+1
⋅
⋅
⋅
\cdot\cdot\cdot
⋅⋅⋅ 种选择。根据乘法原理有:
d
(
x
)
=
(
1
+
ω
1
)
×
(
1
+
ω
2
)
×
⋅
⋅
⋅
×
(
1
+
ω
m
)
d(x) = (1+\omega_1) \times (1+\omega_2) \times \cdot\cdot\cdot \times (1+\omega_m)
d(x)=(1+ω1)×(1+ω2)×⋅⋅⋅×(1+ωm)
同样分两种情况讨论。
当 i%prime[j] == 0 时:
由于 prime[j] 是 i×prime[j] 的最小质因子,所以在对 i×prime[j] 进行因式分解时,
ω
1
\omega1
ω1 可以有多一种选择。
当
d
(
i
)
=
(
1
+
ω
1
)
×
(
1
+
ω
2
)
×
⋅
⋅
⋅
×
(
1
+
ω
m
)
d(i) = (1+\omega_1) \times (1+\omega_2) \times \cdot\cdot\cdot \times (1+\omega_m)
d(i)=(1+ω1)×(1+ω2)×⋅⋅⋅×(1+ωm) 时,
d ( i × p r i m e [ j ] ) = ( 2 + ω 1 ) × ( 1 + ω 2 ) × ⋅ ⋅ ⋅ × ( 1 + ω m ) d(i \times prime[j]) = (2+\omega_1) \times (1+\omega_2) \times \cdot\cdot\cdot \times (1+\omega_m) d(i×prime[j])=(2+ω1)×(1+ω2)×⋅⋅⋅×(1+ωm)
另外用一个数组 omega[i],保存 i 的最小质因子的个数。
所以:
d
(
i
×
p
r
i
m
e
[
j
]
)
=
d
(
i
)
/
(
o
m
e
g
a
[
i
]
+
1
)
×
(
o
m
e
g
a
[
i
]
+
2
)
d(i \times prime[j])=d(i) / (omega[i]+1) \times (omega[i]+2)
d(i×prime[j])=d(i)/(omega[i]+1)×(omega[i]+2)
同时
o
m
e
g
a
[
i
×
p
r
i
m
e
[
j
]
]
=
o
m
e
g
a
[
i
]
+
1
omega[i \times prime[j]]=omega[i]+1
omega[i×prime[j]]=omega[i]+1
当 i%prime[j] != 0 时:
此时
i
×
p
r
i
m
e
[
j
]
i \times prime[j]
i×prime[j] 的所有因子可以分成两部分,一部分是所有 i 的因子;另一部分是每一个 i 的因子乘以
p
r
i
m
e
[
j
]
prime[j]
prime[j] ,可以看出两部分数值上相等,所以
d
(
i
×
p
r
i
m
e
[
j
]
)
=
d
(
i
)
×
2
d(i \times prime[j])=d(i) \times 2
d(i×prime[j])=d(i)×2
4. 欧拉筛法求约数和
我们用 S(n) 来表示 n 的所有约数之和。
公式:
S
(
n
)
=
(
1
+
P
1
+
P
1
2
+
⋅
⋅
⋅
+
P
1
ω
1
)
×
(
1
+
P
2
+
P
2
2
+
⋅
⋅
⋅
+
P
2
ω
2
)
×
⋅
⋅
⋅
×
(
1
+
P
m
+
P
m
2
+
⋅
⋅
⋅
+
P
m
ω
m
)
S(n)=(1+P_1+P_1^{2}+\cdot\cdot\cdot+P_1^{\omega_1}) \times\\(1+P_2+P_2^{2}+\cdot\cdot\cdot+P_2^{\omega_2}) \times \cdot\cdot\cdot \times\\(1+P_m+P_m^{2}+\cdot\cdot\cdot+P_m^{\omega_m})
S(n)=(1+P1+P12+⋅⋅⋅+P1ω1)×(1+P2+P22+⋅⋅⋅+P2ω2)×⋅⋅⋅×(1+Pm+Pm2+⋅⋅⋅+Pmωm)
证明略。
用
p
s
u
m
[
i
]
psum[i]
psum[i] 表示 i 的最小质因子 p 的一个形如
1
+
P
+
P
2
+
⋅
⋅
⋅
+
P
ω
1+P+P^2+\cdot\cdot\cdot+P^{\omega}
1+P+P2+⋅⋅⋅+Pω 的等比数列的和。
仍然分两种情况,i % prime[j] == 0 时:
S
(
i
×
p
r
i
m
e
[
j
]
)
=
(
1
+
P
1
+
P
1
2
+
⋅
⋅
⋅
+
P
1
ω
1
+
P
1
ω
1
+
1
)
×
(
1
+
P
2
+
P
2
2
+
⋅
⋅
⋅
+
P
2
ω
2
)
×
⋅
⋅
⋅
×
(
1
+
P
m
+
P
m
2
+
⋅
⋅
⋅
+
P
m
ω
m
)
S(i \times prime[j])=(1+P_1+P_1^{2}+ \cdot\cdot\cdot +P_1^{\omega_1}+ P_1^{\omega_1+1}) \times\\ (1+P_2+P_2^{2}+ \cdot\cdot\cdot+ P_2^{\omega_2}) \times \cdot\cdot\cdot \times (1+P_m+P_m^{2}+ \cdot\cdot\cdot+ P_m^{\omega_m})
S(i×prime[j])=(1+P1+P12+⋅⋅⋅+P1ω1+P1ω1+1)×(1+P2+P22+⋅⋅⋅+P2ω2)×⋅⋅⋅×(1+Pm+Pm2+⋅⋅⋅+Pmωm)
由于
p
r
i
m
e
[
j
]
prime[j]
prime[j] 就是
i
×
p
r
i
m
e
[
j
]
i \times prime[j]
i×prime[j] 的最小质因子,
此时:
p
s
u
m
[
i
×
p
r
i
m
e
[
j
]
]
=
p
s
u
m
[
i
]
∗
p
r
i
m
e
[
j
]
+
1
psum[i \times prime[j]]=psum[i]*prime[j]+1
psum[i×prime[j]]=psum[i]∗prime[j]+1
同时:
S
[
i
×
p
r
i
m
e
[
j
]
]
=
S
[
i
]
/
p
s
u
m
[
i
]
×
p
s
u
m
[
i
×
p
r
i
m
e
[
j
]
]
S[i \times prime[j]]=S[i] / psum[i] \times psum[i \times prime[j]]
S[i×prime[j]]=S[i]/psum[i]×psum[i×prime[j]]
i % prime[j] != 0 时:
p
s
u
m
[
i
×
p
r
i
m
e
[
j
]
]
=
p
r
i
m
e
[
j
]
+
1
psum[i \times prime[j]]=prime[j]+1
psum[i×prime[j]]=prime[j]+1
S
[
i
×
p
r
i
m
e
[
j
]
]
=
S
[
i
]
×
p
s
u
m
[
i
×
p
r
i
m
e
[
j
]
]
S[i \times prime[j]]=S[i] \times psum[i \times prime[j]]
S[i×prime[j]]=S[i]×psum[i×prime[j]]
(等价于
S
[
i
]
×
(
p
r
i
m
e
[
j
]
+
1
)
S[i] \times (prime[j]+1)
S[i]×(prime[j]+1))
5. 代码
#include <cstdio>
int N;
int visit[1001], prime[1001], pa;
int phi[1001];
int sum[1001], d[1001]; //最小质因子个数 因子个数
int psum[1001], s[1001]; //1+p+p^2... 因数和
void Euler(int n)
{
phi[1] = 1; //1的欧拉函数是1 规定
for(int i=2;i<=n;i++)
{
if(!visit[i])
{
prime[pa++] = i;
phi[i] = i-1; //素数的欧拉函数phi[i] = i-1
d[i] = 2; //素数的因子只有1和本身
sum[i] = 1; //素数的最小质因子是自己
psum[i] = i+1; //只有一个质因子且指数为1
s[i] = i+1; //i的因子有 1 和 i 两个 因数和 i+1
}
for(int j=0;j<pa&&i*prime[j]<=n;j++)
{
visit[i*prime[j]] = 1;
if(i%prime[j]==0)
{
phi[i*prime[j]] = phi[i]*prime[j];
sum[i*prime[j]] = sum[i]+1;
d[i*prime[j]] = d[i]/(sum[i]+1)*(sum[i]+2);
psum[i*prime[j]] = psum[i]*prime[j]+1;
s[i*prime[j]] = s[i]/psum[i]*psum[i*prime[j]];
break;
}
phi[i*prime[j]] = phi[i]*(prime[j]-1);
sum[i*prime[j]] = 1;
d[i*prime[j]] = d[i]*2; //i本身的因子 i的每个因子*prime[j]
psum[i*prime[j]] = 1+prime[j];
s[i*prime[j]] = s[i]*(1+prime[j]);
}
}
}
void test(int n)
{
for(int i=2;i<=n;i++)
{
printf("%d: \n", i);
if(!visit[i])
printf("%d是素数\n", i);
else
printf("%d不是素数\n", i);
printf("%d的欧拉函数phi[%d]=%d\n", i, i, phi[i]);
printf("%d的因子个数为%d\n", i, d[i]);
printf("%d的所有因子和为%d\n", i, s[i]);
}
}
int main()
{
Euler(100);
test(100);
return 0;
}
6. 例题
筛素数: 洛谷P3383 【模板】线性筛素数.
求欧拉函数:UVA10299 Relatives.
筛法欧拉函数: SP4141 ETF - Euler Totient Function.
求欧拉函数: 洛谷P2158 [SDOI2008]仪仗队.