埃氏筛
埃氏筛的原理就是每次在素数表中将素数 p p p的倍数划去,实现简单。
时间复杂度: O ( n log n ) O(n\log n) O(nlogn)。
空间复杂度: O ( n ) O(n) O(n)。
int prime[N], kp;
bool is_prime[N];
void sieve(int k){
for (int i = 0; i <= k; ++ i) is_prime[i] = true;
is_prime[0] = is_prime[1] = false;
kp = 0;
for (int i = 2; i <= k; ++ i) if (is_prime[i]){
prime[kp ++] = i;
for (int j = i + i; j <= k; j += i) is_prime[j] = false;
}
}
区间筛
用途:筛出区间 [ a , b ] [a, b] [a,b]中的素数。
注意到区间 [ a , b ] [a, b] [a,b]内的合数的最小质因子一定在 [ 2 , b ] [2, \sqrt{b}] [2,b]内,所以先用埃氏筛筛出 [ 2 , b ] [2, \sqrt{b}] [2,b]内素数,再用这些素数去筛 [ a , b ] [a, b] [a,b]区间内的素数。
时间复杂度: O ( n log n ) O(n \log n) O(nlogn)。
空间复杂度: O ( n ) O(n) O(n)。
int prime[N], kp;
bool is_prime[N], seg_prime[N];
void seg_sieve(LL l, LL r){
for (LL i = 0; i * i <= r; ++ i) is_prime[i] = true;
for (LL i = l; i <= r; ++ i) seg_prime[i - l] = true;
is_prime[0] = is_prime[1] = false;
for (LL i = 2; i * i <= r; ++ i) if (is_prime[i]){
for (LL j = i + i; j * j <= r; j += i) is_prime[j] = false;
for (LL j = max(2ll, (l + i - 1) / i) * i; j <= r; j += i)
seg_prime[j - l] = false;
}
kp = 0;
if (l <= 0 && 0 <= r) seg_prime[0 - l] = false; // 特判0
if (l <= 1 && 1 <= r) seg_prime[1 - l] = false; // !!! 特别提醒要特判1
for (LL i = l; i <= r; ++ i) if (seg_prime[i - l])
prime[kp ++] = i;
}