Skip to content

一、线性筛 ​

易发现时间复杂度为 O(nn) 的埃式筛法存在缺陷:一个数有可能被多个质数筛掉。

如 24,他在 2×12 时被筛了一遍,3×8 时又被筛了一遍,十分浪费时间。

线性筛就是让每个数只会被一个质数筛去,这个质数就是被筛的合数的最小质因子。

算法代码:

cpp
namespace Eular{
	int prime[N],tot;
	bool isprime[N];
	void eular(int x){
		memset(isprime,true,sizeof isprime);
		isprime[1]=false;
		for(int i=2;i<=x;i++){
			if(isprime[i])prime[++tot]=i;
			for(int j=1;j<=tot and i*prime[j]<=x;j++){
				isprime[i*prime[j]]=false;
				if(!(i%prime[j]))break;
			}
		}
	}
}using namespace Eular;

为什么当 imodprimej=0 时,就可以进入下一个合数了呢?

举例:当 i=21 时,prime={0,2,3,5,7,11,13,17,19}。

当遍历到 prime2 时,21=3×7,如果此时不停止 21 的工作,那么下一个被筛的数 5×21=105 就是被 5 筛掉的,而显然的,根据线性筛工作的原理,105 应该被 3×(7×5),也就是 3×35 筛。

二、欧拉函数 ​

1. 定义 ​

欧拉函数 φ(n) 表示小于等于 n 且与 n 互质的正整数个数。

如 φ(12)=4(1,5,7,11)。

特别的,φ(1)=1。

2. 解法 ​

可以用容斥原理很快的求出来。

如求 12 的,用 Ai 表示小于等于 12 的数中,i 的倍数的个数,那么答案为 +A1−A2−A3+A2×3。

理解例子后,再求更通用的公式:

分解 n 的质因子,设 n=p1t1p2t2p3t3…pmtm,其中序列 p 的数全为质数且不重复。

设 Ai 表示小于等于 n 且是 pi 的倍数的自然数集合,则 |Ai|=⌊npi⌋(1≤i≤m)。

因 p 序列中全为质数,所以 p 里的所有数互质,所以 pi 与 pj 的最小公倍数是 pipj,所以 |Ai∩Aj|=npipj(i≠j,1≤i,j≤m)。

由容斥原理,可得:

3. 定理 ​

(1). 若 n 是质数,φ(n)=n−1。 ​

因为 n 是质数,那么 n 的分解质因数为:p={n}。

∴φ(n)=n(1−1n)=n−1

(2). 已知 q 是质数,若 nmodq=0,则 φ(nq)=qφ(n),否则 φ(nq)=(q−1)φ(n)。 ​

先证明第一点。

用同第二章第 2 节的方法分解 n 的质因子得到序列 p。

∵nmodq=0,且 q 是质数,

∴q∈p。

将 q 从集合 p 中删去。

∴φ(nq)=nq(1−1q)∏i=1m(1−1pi),

qφ(n)=qn(1−1q)∏i=1m(1−1pi)。

∴φ(nq)=qφ(n)。

再证明第二点。

同理得到 p,但此时 q∉p。

∴φ(nq)=nq(1−1q)∏i=1m(1−1pi)=(nq−n)∏i=1m(1−1pi),

(q−1)φ(n)=(q−1)n∏i=1m(1−1pi)=(nq−n)∏i=1m(1−1pi)。

∴φ(nq)=(q−1)φ(n)。

三、积性函数 ​

1. 定义 ​

若在正整数域中一个函数 f(x) 对于任意 gcd(x,y)=1 的 x,y 都满足 f(xy)=f(x)f(y),则称 f(x) 是一个积性函数。

2. O(n) 求 φ(1)∼φ(n) ​

(1). 证明 φ(x) 是积性函数 ​

设 n 与 m 互质,他们的质因子的数列分别是 pn,pm,且个数分别为 cntn,cntm。

因为 n 与 m 互质,所以 pn 与 pm 里的数互不相同。

则 φ(n)φ(m)

=nm∏i=1cntn(1−pni)∏i=1cntm(1−pmi)

=φ(nm)。

(2). 解法 ​

设 q 是 nq 的最小质因子,由第二章第 3 节的定理可得:

φ(nq)={n−1n=qqφ(n)nmodq=0(q−1)φ(n)nmodq≠0

这样就可以一边欧拉筛一边递推了。

cpp
namespace Phi{
	int prime[N],tot,phi[N];
	bool isprime[N];
	void getphi(int x){
		memset(isprime,true,sizeof isprime);
		isprime[1]=false;
		phi[1]=1;
		for(int i=2;i<=x;i++){
			if(isprime[i]){
				prime[++tot]=i;
				phi[i]=i-1;
			}
			for(int j=1;j<=tot and i*prime[j]<=x;j++){
				isprime[i*prime[j]]=false;
				if(i%prime[j])phi[i*prime[j]]=(prime[j]-1)*phi[i];
				else{
					phi[i*prime[j]]=prime[j]*phi[i];
					break;
				}
			}
		}
	}
}using namespace Phi;

3. 更多积性函数:d(x) ​

(1). 定义 ​

(2). 证明 d(x) 是积性函数 ​

(3). 解法 ​

最近更新