总结-筛素数
埃拉托斯特尼筛法
如上图所示,朴素的埃氏筛法从2~n对于每个没有被筛去的数——即素数,从该素数开始将i的各个倍数依次删去.
int not_pri[maxn],pri[maxn],pcnt;
void init_pri(int n)
{
not_pri[0]=not_pri[1]=1;
for(int i=2;i<=n;i++) {
if(!not_pri[i]) pri[pcnt++]=i;
for(int j=i*2;j<=n;j+=i) not_pri[j]=1;
}
}
其时间复杂度为 n/2+n/3+...+n/n=O(nlogn)
当然可以对其进行优化,对于不是素数的数,不需要对其倍数进行删去操作,而且对于每一个素数
p
开始筛的位置应该是
int not_pri[maxn],pri[maxn],pcnt;
void init_pri(int n)
{
not_pri[0]=not_pri[1]=1;
for(int i=2;i<=n;i++) if(!not_pri[i]) {
pri[pcnt++]=i;
for(int j=i*i;j<=n;j+=i) not_pri[j]=1;//注意i*i可能会溢出
}
}
时间复杂度为
O(nloglogn)
参考/图片来源:
wikiwand 英文
wikiwand 中文
线性筛
对于任意一个合数将其拆分成最小因数和最大因数,且最小因数为素数.因为若最小因数不是素数,一定可以将其拆分成两个数相乘形式,这个数一定不是最小因数.
那么就可以用当前数和已有素数来筛,那么应该筛到什么时候.
对于一个数 N ,有
N=p∗M
若 M 中存在p ′ <p ,则有 N=p ′ ∗M ′ ,此时 M ′ >M .
所以当
M%p=0
时,就应该停止继续枚举更大的
p
,因为之后枚举的
int not_pri[maxn],pri[maxn],pcnt;
void init_pri(int n)
{
not_pri[0]=not_pri[1]=1;
for(int i=2;i<=n;i++) {
if(!not_pri[i]) pri[pcnt++]=i;
for(int j=0;j<pcnt&&pri[j]*i<=n;j++) {
not_pri[pri[j]*i]=1;
if(i%pri[j]==0) break;
}
}
}