欧拉筛
欧拉筛是较之于埃氏筛的一种更高效的素数筛法。
线性筛,复杂度为O(n)。与埃氏筛相比,不会对已经被标记过的合数再进行重复标记,故效率更高。欧拉筛将合数分解为 (最小质因数 * 一个合数) 的形式,通过最小质因数来判断当前合数是否已经被标记过。
我的代码
int prm[N],tot=0; //prm为质数组,tot记质数个数
bool boo[N]; //标记是否为质数
void prime(){
memset(boo,0,sizeof(boo)); //标记质数为0,合数为1;
for(int i=2;i<=N-7;i++){
if(!boo[i]){ //如果还没被标为合数
prm[++tot]=i; //i就是第tot+1个质数
}
for(int j=1;j<=tot&&i*prm[j]<=N-7;j++){
boo[i*prm[j]]=1; //用i做倍数,第j个质数的i倍都是合数
if(i%prm[j]==0){ //核心步骤
break;
}
}
}
}
对于核心步骤,引用一下别人的解释
对于 i%prime[j] == 0 就break的解释 :当 i是prime[j]的倍数时,i = kprime[j],如果继续运算 j+1,i * prime[j+1] = prime[j] * k prime[j+1],这里prime[j]是最小的素因子,当i = k * prime[j+1]时会重复,所以才跳出循环。
举个例子 :i = 8 ,j = 1,prime[j] = 2,如果不跳出循环,prime[j+1] = 3,8 * 3 = 2 * 4 * 3 = 2 * 12,在i = 12时会计算。因为欧拉筛法的原理便是通过最小素因子来消除。
————————————————
版权声明:本文为CSDN博主「彤云望月」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39763472/article/details/82428602
若将一个合数n=i * prm[j],称为n被prm[j]标记,若i%prm[j]==0,那么合数m=i%prm[j+1]不需被prm[j+1]标记,随着i增长,它会被它的最小质因子prm[j]标记。
欧拉函数
在上述代码的基础上增加数组phi[N],可快速求出欧拉函数表。并没有用欧拉函数的公式
p1…pn是x的所有质因数
在数论,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目(因此φ(1)=1)。
特性 :
1.若a为质数,phi[a]=a-1;
2.若a为质数,b mod a=0,phi[a*b]=phi[b]*a
3.若a,b互质,phi[a*b]=phi[a]*phi[b](当a为质数时,if b mod a!=0 ,phi[a*b]=phi[a]*phi[b])
void euler(){
memset(boo,0,sizeof(boo));
phi[1]=1;
for(int i=2;i<=N-7;i++){
if(!boo[i]){
prm[++tot]=i;
phi[i]=i-1; //新增行,特性1
}
for(int j=1;j<=tot&&i*prm[j]<=N-7;j++){
boo[i*prm[j]]=1;
if(i%prm[j]==0){
phi[i*prm[j]]=phi[i]*prm[j]; //新增行,特性2
break;
}
else phi[i*prm[j]]=phi[i]*phi[prm[j]]; //新增行,特性3
}
}
}