求1e11以内的素数

  有两种做法,一种是打表,另一种是直接求。

 

打表

将1e11每隔len(len=2000w)个数字统计一下该区间内素数的个数,比如cnt[1] 表示[1,len]以内有多少个素数,cnt[2]表示[len+1,2*len】以内有多少个素数,依次类推。

然后维护一下前缀和,sum[i] = cnt[1] + ....+ cnt[i]

那么给定一个数字n,求[1,n]以内有多少个素数, 那么只要统计一下sum[n/len],然后再统计一下区间[n/len*len+1, n/len*len + n%len],由于这个内最多只有2000w个,那么只要对该区间内的数字进行筛法求素数,然后统计该区间内素数的个数就可以了。

任意区间内素数的个数

所以关键是如果求任意区间内素数的个数, 例如要求区间[a, b]内有多少个数字, 因为该区间内任意合数字的最大最小质因数不会超过sqrt(b),所以只要先求出区间[2,sqrt(b)]内的素数表,那么就可以用该素数表去筛去区间[a,b]内的所有合数。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef long long LL;
/*
 * 要求区间[a,b]以内的素数, 那么该区间内所有合数的最小质因数绝对不超过sqrt(b),
 * 所以只要求出[2,sqrt(b)]以内的所有素数,然后用这些素数筛去区间[a,b]内的所有合数即可
 * 要开的数组的大小
 * M > b - a
 * N > sqrt(b)
*/
const int N = 1000000;
const int M = 10000000;

bool is_prime[N];
int prime[N], cnt;
void get_prime(){
    for(int i=3; i<N; ++i)
        is_prime[i] = true;
    cnt = 0;
    prime[cnt++] = 2;
    for(LL i=3; i<N; i+=2){
        if(is_prime[i]){
            prime[cnt++] = i;
            for(LL j=i*i; j<N; j+=2*i){
                is_prime[j] = false;
            }
        }
    }
}

bool is_prime2[M];
int get_prime2(LL l, LL r){
    for(LL i=0; i<=r-l; ++i)
        is_prime2[i] = true;

    for(LL i=0; i<cnt && (LL)prime[i]*prime[i]<=r; ++i){
        /* (l+prime[i]-1)/prime[i]*prime[i] 得到最接近l的prime[i]的倍数是多少 */
        for(LL j=max(2LL, (l+prime[i]-1)/prime[i])*prime[i]; j<=r; j+=prime[i]){
            is_prime2[j-l] = false;
        }
    }
    int res = 0;
    //会把0和1当做素数,所以要减去
    if(l==0)
        res -= 2;
    if(l==1)
        res -= 1;
    for(LL i=0; i<=r-l; ++i){
        res += is_prime2[i];
        /* printf("%lld %d\n", i+l, is_prime2[i]); */
    }

    return res;
}
int main()
{
    /* freopen("in.txt","r",stdin); */
    /* freopen("out.txt","w",stdout); */
    get_prime();
    cout << get_prime2(1, 10000000) << endl;
    return 0;
}

 

posted @ 2016-09-19 13:21  justPassBy  阅读(1421)  评论(0编辑  收藏  举报