素数筛法
Luogu P3383 线性筛素数
给定一个范围n,有q个询问,每次输出第k小的素数
需要在线性时间范围内
埃氏筛法
从小到大枚举每个数,
如果当前数没划掉,必定是质数,记录该质数
枚举当前质数的倍数,必定是合数 划掉合数
// j 从 i * i 开始枚举
vector<int> vis(n); // 为合数
vector<int> prim(n); // 记录质数
int cnt = 0; // 质数个数
void Eratosthenes(int n) {
for (i64 i = 2; i < n; i ++) {
if (!vis[i]) {
prim[cnt++] = i;
for (i64 j = i * i; j <= n; j += i) vis[j] = 1;
}
}
}
线性筛法(欧拉筛)
从小到大枚举每个数
-
如果当前数没划掉,必定是质数,记录该质数
-
枚举已记录的质数(如果合数已越界则中断)
-
合数未越界,则划掉合数
-
条件
i%p == 0,保证合数只被最小质因子划掉-
若 i 是质数,则最多枚举到自身中断
-
若 i 是合数,则最多枚举到自身的最小质数中断
-
-
vector<int> vis(n);
vector<int> prim(n);
int cnt = 0;
void get_prim(int n) {
for (int i = 0; i <= n; i ++) {
if (!vis[i]) prim[cnt ++] = i;
for (int j = 1; 1ll * i * prim[j] <= n; j ++) {
vis[i * prim[j]] = 1;
if (i % prim[j] == 0) break;
}
}
}