【代码超详解】洛谷 P3383 【模板】线性筛素数(埃氏筛法打表 · 已优化)

一、题目描述

题目描述

如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内)

输入格式

第一行包含两个正整数N、M,分别表示查询的范围和查询的个数。

接下来M行每行包含一个不小于1且不大于N的整数,即询问该数是否为质数。

输出格式

输出包含M行,每行为Yes或No,即依次为每一个询问的结果。

输入输出样例

输入 #1

100 5
2
3
4
91
97

输出 #1

Yes
Yes
No
No
Yes

说明/提示

时空限制:500ms 128M

数据规模:

对于30%的数据:N<=10000,M<=10000

对于100%的数据:N<=10000000,M<=100000

样例说明:

N=100,说明接下来的询问数均不大于100且不小于1。

所以2、3、97为质数,4、91非质数。

故依次输出Yes、Yes、No、No、Yes。

二、算法分析说明与代码编写指导

一、质数的埃氏筛法
1、用途:快速选出一定数量的质数。
2、算法内容:
埃拉托斯特尼(Eratosthenes)筛法(埃氏筛法)  要筛选出不大于n的质数,排除sqrt(n)以内全部质数的倍数即可。
(Eratosthenes(前276—前194),古希腊数学家)
设需要生成前若干个质数,prime数组用于存储已经验证为质数的数。
设a为当前正在验证是否为质数的正整数,t = sqrt(a)为需要试除的范围。
用已知的质数去除a,如果能整除,a就有除了1和a本身以外的因数,终止当前的判断,准备判断a+1。
为什么只用试除到t = sqrt(a)呢,因为因数是一对一对的,例如:
100 的因数有:1 2 4 5 10 20 25 50 100。我们发现,1 * 100 = 2 * 50 = 4 * 25 = 5 * 20 = 10 * 10。
如果验证到sqrt(a)后,还没有发现第3个a的因数,自然也不会再有了。
换句话说,还是以100为例子,如果找出了因数2,就可以计算出因数50。如果找到了因数4,就可以计算出因数25。
如果验证了某个数d不是a的因子,那么d的倍数也不是a的因子。
比如2不是 a 的因子,那么4 6 8 …… 都不用验证了。比如3不是 a 的因子,那么6 9 12 …… 都不用验证了。
如果要验证是否为a的因子的数d是质数,那么在之前验证过的数及其倍数都不是这个质数d的因数,也就是说d还没有用于验证过。
可见,用质数试除是不能避免的。对于合数来说,如果已知它的一个质因数不是a的因子,那么这个合数也不用再验证是否为a的因子。
意即,要用这个合数去除a,就相当于用a的每个质因数去除a。如果某个质因数不能整除a,那么这个合数也不能整除a。
从几个角度都啰嗦完了,相信总有一种角度适合你的理解。

二、质数的判定
1、用途:迅速判定一个数是否为质数。
2、算法内容:
用埃氏筛法打质数表,打表结果保存在prime数组中。然后判断要验证是否为质数的整数x是否在表的范围内。
如果是,在prime数组内二分搜索x,搜到就是质数,搜不到就不是。
如果x超出了表的范围,就验证x是不是已经打表的质数的倍数。如果都不是,x就是质数。
3、参考代码:(具体看本题AC代码,含埃氏筛法打表,有时候int / unsigned的范围不够用,此时需要自己换类型)
要求:采用本参考代码时,需要先包含头文件<algorithm>,且声明一个prime数组用于存储已经验证的质数,以及
using namespace std; 传入的参数是需要生成的质数的数量。前2个质数23必须要先写入prime数组。额外建立一个变量_PTy,
其类型与prime数组的类型相同,以便decltype关键字自动侦测类型。此外,x的类型不能大于prime数组的类型。
4、注意事项:
x不能超过最大已打表质数的平方,否则会返回错误的结果,从而WA。

三、AC 代码

#include
#include
#include
#pragma warning(disable:4996)
using namespace std;
unsigned prime[6543] = { 2,3 }, _PTy, MaxPrime, * prime_end = prime + sizeof(prime) / sizeof(prime[0]);
inline void genprime(const size_t& _Size) {
	decltype(_PTy) a = 4, t; bool flag = true;
	for (size_t i = 2; i < _Size;) {
		t = sqrt(a), flag = true;
		for (size_t j = 0; prime[j] <= t; ++j)
			if (a % prime[j] == 0) { flag = false; break; }
		if (flag) { prime[i] = a, ++i; }
		++a;
	}
	MaxPrime = prime[_Size - 1];
}
inline bool isprime(const decltype(_PTy)& x) {
	if (x <= MaxPrime)return binary_search(prime, prime_end, x);
	else {
		decltype(_PTy) t = sqrt(x);
		for (size_t j = 0; prime[j] <= t; ++j)
			if (x % prime[j] == 0)return false;
		return true;
	}
}
int main() {
	unsigned n, m, x;
	genprime(6543);
	scanf("%u%u", &n, &m); ++m;
	while (--m) {
		scanf("%u", &x);
		switch (isprime(x)) {
		case 1:puts("Yes"); continue;
		default:puts("No");
		}
	}
	return 0;
}

你可能感兴趣的:(ACM-ICPC)