欧拉筛法
众所周知欧拉筛法一般用于在线性时间内筛选出 1~n 范围内的质数,但是在数论问题中欧拉筛法的用途不仅仅是筛素数,它还可以干其他三件事,只不过这些问题被提及的次数比较少。
欧拉筛法可以干哪些事呢?
求 1~n 之间所有质数
求 1~n 之间所有自然数的欧拉函数 φ(x)
求 1~n 之间每个数的因子个数
求 1~n 之间每个数的因数和
-
筛质数
这个大家应该很熟悉了,这里就写一个关键点吧。
欧拉筛法核心思想:每个合数只被自己的最小质因子筛一次。
对 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],违反了筛法原则。 -
欧拉函数
欧拉函数 φ(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−
Pi
1
)
其中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-1ϕ§=p−1
ϕ ( p k ) = p k − p k − 1 = p k − 1 × ( p − 1 ) \phi(p^k) = pk-p{k-1}=p^{k-1} \times (p-1)ϕ(p
k
)=p
k
−p
k−1
=p
k−1
×(p−1)
对性质二的解释:只有一个数的因子不含质数 p 时,才有可能与 p k p^kp
k
互质。而小于等于 p k p^kp
k
的数中因子包含 p 的数有 p k − 1 p^{k-1}p
k−1
个,即 1 × p 1 \times p1×p,2 × p 2 \times p2×p,⋅ ⋅ ⋅ \cdot\cdot\cdot⋅⋅⋅,p k − 1 × p p^{k-1} \times pp
k−1
×p。从总数 p k p^kp
k
中把他们去除便剩下了与 p k p^kp
k
互质的数。
所以由 (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
∏
m
Pi
ω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])=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)×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)
- 欧拉筛法求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]+1omega[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 2d(i×prime[j])=d(i)×2
- 欧拉筛法求约数和
我们用 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+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
)
证明略。
用 p s u m [ i ] psum[i]psum[i] 表示 i 的最小质因子 p 的一个形如 1 + P + P 2 + ⋅ ⋅ ⋅ + P ω 1+P+P2+\cdot\cdot\cdot+P{\omega}1+P+P
2
+⋅⋅⋅+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+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
)
由于 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]+1psum[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]+1psum[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))
#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;
}