Skip to content
0

一、线性筛

易发现时间复杂度为 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)=415711)。

特别的,φ(1)=1

2. 解法

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

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

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

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

Ai 表示小于等于 n 且是 pi 的倍数的自然数集合,则 |Ai|=npi1im)。

p 序列中全为质数,所以 p 里的所有数互质,所以 pipj 的最小公倍数是 pipj,所以 |AiAj|=npipjij,1i,jm)。

由容斥原理,可得:

3. 定理

(1). 若 n 是质数,φ(n)=n1

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

φ(n)=n(11n)=n1

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

先证明第一点。

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

nmodq=0,且 q 是质数,

qp

q 从集合 p 中删去。

φ(nq)=nq(11q)i=1m(11pi)

qφ(n)=qn(11q)i=1m(11pi)

φ(nq)=qφ(n)

再证明第二点。

同理得到 p,但此时 qp

φ(nq)=nq(11q)i=1m(11pi)=(nqn)i=1m(11pi)

(q1)φ(n)=(q1)ni=1m(11pi)=(nqn)i=1m(11pi)

φ(nq)=(q1)φ(n)

三、积性函数

1. 定义

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

2. O(n)φ(1)φ(n)

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

nm 互质,他们的质因子的数列分别是 pnpm,且个数分别为 cntncntm

因为 nm 互质,所以 pnpm 里的数互不相同。

φ(n)φ(m)

=nmi=1cntn(1pni)i=1cntm(1pmi)

=φ(nm)

(2). 解法

qnq 的最小质因子,由第二章第 3 节的定理可得:

φ(nq)={n1n=qqφ(n)nmodq=0(q1)φ(n)nmodq0

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

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). 解法

最近更新