埃氏筛
原理
根据算术基本定理,每个大于1的数都可以分解成若干个质数的乘积,所以对于一个不是质数的数,只需判断它有质因数即可。埃氏筛(埃拉托斯特尼筛法)其实就是上述过程的逆过程:每枚举到一个质数便把这个质数的倍数打上不是质数的标记。
实现
具体如下:
//筛出1~n的质数
for(int i = 2; i * i <= n; i++){ //只需枚举到sqrt(n)
if(!v[i]){
for(int j = i + i; j * j <= n; j += i){
v[j] = 1;
}
}
}
区间筛
一般筛质数是筛出 1~n 内的质数,有些时候需要找一个区间内质数的个数,而左右边界又比较大,不能直接用前缀和相减算出。例如:
洛谷P1835 素数密度
给定区间[L,R] (L <= R < 2^31,R - L <= 10^6) ,请计算区间中素数的个数。
做法
运用埃氏筛的原理,对于枚举的每个质数,在 1~n 内筛质数的同时,也在 L~R内筛。
//核心代码:
for (int i = 2; ((ll)i * i) <= m; i++) {
if (!v[i]) {
for (int j = 2 * i; ((ll)j * j) <= m; j += i)
v[j] = 1;
int k;
//最主要的是初始值,并不是从n开始筛起,而是从[n,m]中第一个质数i的倍数开始
if (n % i == 0)
k = n;
else {
k = n / i;
k = k * i + i;
}
for (ll j = k; j <= m; j += i) {
vis[j - n] = 1;
}
}
}