欧拉筛

欧拉筛法
众所周知欧拉筛法一般用于在线性时间内筛选出 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−
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. 欧拉筛法求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

  1. 欧拉筛法求约数和
    我们用 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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值