Concept
指在线性时间
O(n)
用筛选的方法求一些东西的算法。
伪目录
1. 求质数表
2. 筛出欧拉函数φ
Ideas
As we all know,
x=p1a1⋅p2a2⋅...⋅pnan
即
x=∏ni=1piai
其中
pi为第i个质数,ai为其对应的质数
我们还可以通过乘法定理得知,
x的约数共有∏ni=1(ai+1)
个
当然,这是后话了
For prime Numbers table
最简单的,我们使用线性筛法筛质数表
先来看看普通的筛法
fillchar(x,sizeof(x),true);//假设所有数都是质数(Tips x[1]=false)
for i:=2 to n do
if x[i] then //x[i]表示i是否为质数
for j:=2 to n div i do
x[i*j]:=false; //筛掉i*j(非质数)
显然复杂度为
O(n2)
我们发现,有的数字被筛了多次,如24
当然最好的情况是每个数字只被筛1次
看Code之间,先回忆一句话
使每个数字只被筛1次
也许我们需要换个思路(线性筛法)
那线性筛法又是如何做到使每个数字只被筛1次的呢?
这就是我们所需要证明的
Code
fillchar(bz,sizeof(bz),true);
for i:=2 to n do//枚举数i
begin
if(bz[i])then//i为素数
begin
inc(tot);
s[tot]:=i;//素数数组
end;
for j:=1 to tot do
begin
bz[i*s[j]]:=false;//筛去i*s[j]
if(i mod s[j]=0)then break;//什么鬼?怎么就Break了?
end;
end;
相信都对if(i mod s[j]=0)then break;
一脸懵逼吧~
这也正是线性筛法的神奇所在
好了不说废话
用上
x=∏ni=1piai
∵ 为使令循环break掉的就是 p1 (最小的素数)
∴ 不能让 x被pl(l>1)筛掉
设x=p1∗a=pl∗bpl∗b=∏ni=1piai∗b
=(u∗p2∗p3∗...∗pm−1∗pm)∗p1
=a∗p1
显然 a<b
∵
a没有比
p1
要小的质因数
∴
一定会枚举到
b
前用
∴
每个
x
只会被
至于某些人问会不会筛掉质数……
我推荐给你一个小学奥数班!
筛出欧拉函数φ
读作φ(fai)
φ(n)为小于n并与n互质的数的个数,是积性函数
即
如果gcd(a,b)=1那么φ(a∗b)=φ(a)∗φ(b)
另
φ(1)=1
性质
-
如果x为素数,那么φ(x)=x−1
小于 x 的数不都与x 互质吗? -
如果x为素数,那么φ(xk)=xk−xkx=xk−1(x−1)
显然只有 x 的倍数才不互质xk -
φ(x)=∏kj=1φ(pjaj)
φ(x) 为积性函数
于是乎~
设
x=p1
由性质2得
①φ(xk)=xk−1(x−1)
②φ(xk+1)=xk(x−1)
①代入②
φ(xk+1)=φ(xk)⋅x
φ(x∗i)
=φ(xa1+1)∗φ(p2a2)∗....∗φ(pkak)
=x∗φ(xa1)∗φ(p2a2)∗....∗φ(pkak)
=x∗φ(i)
若x|i那么φ(i∗x)=φ(i)∗x
否则φ(i∗x)=φ(i)∗φ(x)=φ(i)∗(x−1)
Code
恕暂不提供Pascal语言
int prime[M/3],phi[M];
bool flag[M];
void get_prime()
{
int i,j,k;
memset(flag,false,sizeof(flag));
k=0;
for(i=2;i<M;i++){
if(!flag[i]){
prime[k++]=i;
phi[i]=i-1;
}
for(j=0;j<k&&i*prime[j]<M;j++){
flag[i*prime[j]]=true;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
Reference
线性筛法求素数的原理与实现 百度文库
约数详细分析By ColdChair
线性筛法相关By jokerwyt
线性筛法求素数By XianHaoMing