素数

求从1...n的素数: 埃氏筛, 快速线性筛. 

埃氏筛

// 1e8 
// 2 * i  2859
// 1ll * i * i 1980
bool prime[maxn];int get(int size) {
    int cnt = 0;
    for (int i=0; i<size; ++i) prime[i] = true;
    prime[0] = prime[1] = false;
    for (int i=2; i<size; ++i) {
        if (prime[i]) {
            cnt++;
            for (long long k=1ll*i*i; k<size; k+=i) {  // 1ll * i * i 注意要用 long long 因为int容易爆. 
                prime[k] = false;
            }    
        }
    }
    return cnt;
}

快速线性筛:(近似线性)

// 1e8  1232
int prime[maxn];
int isNotPrime[maxn];

int get(int size) {
    int cnt = 0;
    isNotPrime[0] = isNotPrime[1] = 1;
    for (int i=2; i<size; ++i) {
        if (!isNotPrime[i]) 
            prime[cnt++] = i;
        for (int j=0; j<cnt && i*prime[j]<size; j++) {
            isNotPrime[i * prime[j]] = 1;
            if (! (i % prime[j])) break;
        }
    }    
    return cnt;
}
// 取某一段大区间的素数 区间长度1e6左右的. 
// 先预处理2...sqrt(最大数)之间的素数表.
// 然后 把数移动到[left, right]上,然后筛. 
bool isprime[maxn];
void get2(int left, int right, int old_cnt) {  // 求[left, right] 区间的素数 old_cnt是素数表的素数(先预处理的素数表 [2..Sqrt(Max_Value)]的素数表). 
    int i, j;
    if (left == 1) left++;
    // 素数筛 
    for (i=0; i<maxn; ++i) isprime[i] = true;
    for (i=0; i < old_cnt; ++i) {
        if (prime[i] > right) break;
        for (ll j= 1ll * (left / prime[i]) * prime[i]; j<=right; j+=prime[i]) {    // 注意 long long 不然可能会爆. 
            if (j < 1ll*left || j==1ll*prime[i]) continue;
            isprime[right - j] = false;
        }
    }
    int len = right - left;
    for (i=len; i>=0; --i) {
        if (isprime[i]) {
            // 对应素数是 right - i 
        }
    }
}
原文地址:https://www.cnblogs.com/cgjh/p/9633478.html