1、埃氏筛法
给定整数n,请问n以内有多少个素数?(n≤106)
思路:首先,将2到n范围内的所有整数写下来。其中最小的数字2是素数。将表中所有2的倍数都划去。表中剩余最小的数字是3,它不能被更小的素数整除,所以是素数。再将表中3的倍数都划去。以此类推,如果表中最小的数字是m时, m 就是素数。像这样反复操作,就能以此枚举n以内的素数。
int pri[Max_n]; //第i个素数
bool vis[Max_n];//为false表示i是素数
int Prime(int n){
int k=0;
memset(vis,0,sizeof(vis));
for(int i=2;i<=n;i++){
if(!vis[i]){
pri[k++]=i;
for(int j=2*i;j<=n;j+=i)vis[j]=true;
}
}
return k;
}
2、区间筛法
给定整数a和b,请问区间[a,b)内有多少个素数?(a<b≤1012,b-a≤106)
思路:b以内的合数的最小质因数一定不超过√b。如果有√b以内的素数表的话,就可以把埃氏筛法运用在[a,b)上了。也就是说,先分别做好[2,√b)的表和[a,b)的表,然后从[2,√b)的表中筛得素数的同时,也将其倍数从[a,b)的表中划去,最后剩下的就是[a,b)内的素数了。
bool v1[Max_n1]; //数组大小为sqrt(b)
bool v2[Max_n2]; //数组大小为b-a
ll Prime(ll a,ll b){
for(ll i=0;i*i<b;i++)v1[i]=true;
for(ll i=0;i<b-a;i++)v2[i]=true;
for(ll i=2;i*i<b;i++){
if(v1[i]){
for(ll j=2*i;j*j<b;j+=i)v1[j]=false; //筛[2,b)
for(ll j=max(2LL,(a+i-1)/i)*i;j<b;j+=i)v2[j-a]=false; //筛[a,b)
//2LL是2的长整数形式
//((a+i-1)/i)*i是符合>=a最小是i倍数的数
}
}
ll k=0;
for(ll i=0;i<b-a;i++){
if(v2[i])k++;
}
return k;
}