[数据结构与算法-07]欧拉筛
欧拉筛
用途
快速查找区间内的所有素数
思路
-
目标是n以内的所有素数,用isNotPrime[n]判断n是否为素数,1代表是非素数,0代表是素数,prime[]用来记录找出的素数
-
筛除合数,质数筛掉自己的质数倍
-
为了提高速度,应避免重复筛除(若从2就筛掉了所有偶数,之后所有对偶数的筛查都是多余)
-
保证当前质数只筛除只能被自己筛除的数
- 比如4只能被2筛除而6不是
- 实现方法:if (i%prime[j]==0) break;
- 解释:若i%prime[j]==0,i是prime[j]的倍数,若此时不break,下个数i*prime[j+1]将会被筛除,而这个数在之后一定会被prime[j]筛除,不必现在就筛除,不然到时候就重复了
代码实现
for (int num = 2; num <= n; num++){
// 判断是否是素数
if (isPrime[num]) {
// 记录
prime[cnt] = i;
// 记录找到的素数个数
cnt++;
}
for (int j = 0; j < cnt && i*primes[j]<=maxn; j++){
// 用i排除
isPrimes[i*prime[j]] = 0;
// 关键
if (i%prime[j]==0)break;
}
}
P3383 【模板】线性筛素数
题目背景
本题已更新,从判断素数改为了查询第 kk 小的素数
提示:如果你使用cin来读入,建议使用std::ios::sync_with_stdio(0)来加速。题目描述
如题,给定一个范围 nn,有 qq 个询问,每次输出第 kk 小的素数。
输入格式
第一行包含两个正整数 n,qn,q,分别表示查询的范围和查询的个数。
接下来 qq 行每行一个正整数 kk,表示查询第 kk 小的素数。
输出格式
输出 qq 行,每行一个正整数表示答案。
输入输出样例
输入 #1复制
100 5 1 2 3 4 5输出 #1复制
2 3 5 7 11说明/提示
【数据范围】
对于 100%100% 的数据,n = 10^8n=108,1 \le q \le 10^61≤q≤106,保证查询的素数不大于 nn。Data by NaCly_Fish.
完整解答
利用了bitset对内存大幅优化,速度也有所提升
#include <cstdio>
#include <bitset>
int N, q, k, cnt = 0, prime[6000000];
std::bitset<100000000 + 1> isNotPrime;
int main() {
scanf("%d%d", &N, &q);
for (int i = 2; i <= N; i++) {
if (!isNotPrime[i]) {
prime[cnt] = i;
cnt++;
}
for (int j = 0; j < cnt && i * prime[j] <= N; j++) {
isNotPrime[i * prime[j]] = 1;
if (i % prime[j] == 0)break;
}
}
for (int i = 0; i < q; i++) {
scanf("%d", &k);
printf("%d\n", prime[k-1]);
}
return 0;
}
优化前

优化后


浙公网安备 33010602011771号