今天,我们来介绍三种筛素数的方法:
1、暴力枚举法
复杂度为O(n*sqrt(n))
关键代码:
int ans[Maxn],tot;
bool isprime(int x){
for(int i=2;i*i<=x;i++)
if(x%i==0)
return 0;
return 1;
}
for(int i=2;i<=n;i++)
if(isprime(i))
ans[tot++]=i;
Tips:
经研究,除2、3外质数只能是6n+1,6n-1.因为6n+2、6n+4、6n为2的倍数,6n+3为三的倍数。
优化代码:
int ans[Maxn],tot;
bool isprime(int x){
for(int i=2;i*i<=x;i++)
if(x%i==0)
return 0;
return 1;
}
for(int i=2;i<=n;i++)
if(i%6==1||i%6==5)
if(isprime(i))
ans[tot++]=i;
2、埃氏筛法
每次用未被删除的质数乘1、2、3……知道边界,复杂度为O(nloglogn)
关键代码:
bool prime[Maxn];
void Prime(int n){
for(int i=0;i<=n;i++)
prime[i]=1;
prime[0]=prime[1]=0;
for(int i=2;i*i<=n;i++)
if(prime[i])
for(int j=i*i;j<=n;j+=i)
prime[j]=0;
}
这里有一个小优化,如上,j从i*i出发,因为i*i以下的已被删除了
但是,一个合数可能会被删去多次,如60会被2、3、5同时删去
3、欧拉筛法(线性筛法)
优化埃氏筛法,使得每个质数只删去一次,空间复杂度提高,时间复杂度为O(n)
关键代码:
int ans[Maxn],cnt;
bool prime[Maxn];
void Prime(int n){
for(int i=2;i<=n;i++){
if(!prime[i])
ans[++cnt]=i;
for(int j=1;j<=cnt&&i*ans[j]<=n;j++){
prime[i*ans[j]]=1;
if(!(i%ans[j]))
break;
}
}
}