[数据结构与算法-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;
}

优化前
优化前
优化后
优化后

posted @ 2021-02-27 23:32  ChenHongKai  阅读(153)  评论(0)    收藏  举报
1 2 3
4