埃氏筛法、区间筛法(求素数个数)

版权声明:最后一年,加油~ https://blog.csdn.net/zzti_xiaowei/article/details/79322099

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-a106

思路: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;
}

没有更多推荐了,返回首页