素数:一个数 n ,若不能在[2,n-1]中找到一个能整除 n 的数 d ,则 n 为素数。

试除法判断素数

时间复杂度:图片说明

bool is_prime(int n) {
    if (n <= 1) return false;
    for(int i = 2; i * i <= n; ++ i) {
        if (n % i == 0) return false;
    }
    return true;
}

埃氏筛法

时间复杂度:图片说明
原理:每次筛出一个素数 x,并把 x 的倍数筛出。
注:对于 [ 2 * i,i * i ] 之间的合数会被比 i 更小的素数筛去,所以 j = i * i, 但要防止爆int。

const int maxn = 1e7+1;
const int maxm = 664579 + 1;

bool vis[maxn];
int prime[maxm];  // 1~1e7 中素数个数为 664579

void E_sieve(int n) { // 埃氏筛
    int tot = 0;
    for(int i = 1; i <= n; ++ i) vis[i] = 0;
    for(long long i = 2; i <= n; ++ i) {
        if (vis[i]) continue;
        prime[++tot] = i;
        for(long long j = i * i; j <= n; j += i) {
            vis[j] =  1;
        }
    }
    return tot;
}

欧拉筛(线性筛)

时间复杂度:图片说明
原理:每个合数都是由它的最小质因子筛去。
注: if (i % prime[j] == 0) break; 保证了一个数不会被重复筛去。

const int maxn = 1e8+1;
const int maxm = 5761455 + 1;

bool vis[maxn];
int prime[maxm];  // 1~1e8 之间素数个数为 5761455

int E_sieve(int n) { // 欧拉筛
    int tot = 0;
    for(int i = 1; i <= n; ++ i) vis[i] = 0;
    for(long long i = 2; i <= n; ++ i) {
        if (!vis[i]) prime[++tot] = i;
        for(int j = 1; i * prime[j] <= n; ++ j) {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        }
    }
    return tot;
}

区间筛

const int maxn = 1e6+1;

bool vis[maxn];
int prime[maxn];

int E_sieve(int n) { // 线性筛
    int tot = 0;
    for(int i = 1; i <= n; ++ i) vis[i] = 0;
    for(long long i = 2; i <= n; ++ i) {
        if (!vis[i]) prime[++tot] = i;
        for(int j = 1; i * prime[j] <= n; ++ j) {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0) break;
        }
    }
    return tot;
}

int S_sieve(long long l, long long r) { // 区间筛(埃氏筛)
    int tot = E_sieve(sqrt(r));
    for(long long i = l; i <= r; ++ i) vis[i-l+1] = 0;
    for(int i = 1; i <= tot; ++ i) {  // 用2~sqrt(r)素数筛去l~r之间的素数
        long long t = prime[i];
        if (t * t > r) break;
        long long j = max((l+t-1)/t*t, 2*t); // 素数本身不能被筛
        for(; j <= r; j += t) vis[j-l+1] = 1;
    }
    int res = 0;
    for(long long i = max(l,2ll); i <= r; ++ i) // 1 不是素数
        if (!vis[i-l+1]) res ++;
    return res;
}