<数论>素数筛法

埃氏筛法

介绍

如果我们要得到自然数n以内的全部素数,把不大于根号n的所有素数的倍数剔除,剩下的就是素数。

算法分析

因此如果 x是质数,那么大于x的x的倍数\(2x,3x,4x……kx\)(k是整数)一定不是质数,只要将范围内的数字剔除剩下的就是素数了。是不是很简单_

代码

对于1~n的数字,我们先建立一个数组isprime并且全部赋值为1

	bool isprime[N];
	memset(isprime, 1, sizeof(isprime));

这里也能用vector动态的开辟(推荐)

	vector<bool>isprime(N, 1);//大小为N 默认为1

然后对根号n以内的素数i 然后对其倍数 将其筛掉,标记数组为0

	for (int i = 2; i * i < N; i++)
	{
		if (isprime[i])//如果i是素数 那么就开始剔除它的倍数
		{
			for (int j = i + i; j < N; j=j+i)
			{
				isprime[j] = 0;
			}
		}
	}

对上述筛法进行说明

根据分解定理:合数一定能被分解成几个质数的乘积

当从小到大遍历到数 i 时,倘若它是合数,则它一定是某个小于 \(i\)的质数 \(x\) 的整数 \(k\),既\(i=x*k\),故根据此方法的步骤,当最开始遍历到x的时候,开始筛选x的倍数,会将\(isprime[kx]\)的标记为0,所以我们一会把\((i=kx)\)这个数字筛掉,故从小到大,合数都一定能被之前的素数通过加倍从而筛掉

进阶优化

结论:当我们找到素数x的时候,其实从x*x为起点(而不是i*2)进行筛选即可_

因为对于 小于x 的整数倍\(k, 2x,3x,4x……kx。\)

1、当k为质数的时候,\(kx\)一定会被小于x的质数k,通过加倍筛掉,

2、当k为合数的时候,k可以分解成$ i*(k/i) * x$ [i为k的质因子,并且k/i为整数],所以 当我们之前对质数i进行加倍的时候,一定会把kx筛掉。

所以我们对素数x进行筛的时候,对于小于\(x^2\)的整数 \(k,2x,3x,4x……x^2\)都已经被筛过了,因此从\(x^2\)开始筛即可。
优化后的代码

	for (int i = 2; i * i < N; i++)
	{
		if (isprime[i])//如果i是素数 那么就开始剔除它的倍数
		{
			for (int j =i*i; j < N; j=j+i)
			{
				isprime[j] = 0;
			}
		}
	}

线性筛法

介绍

埃氏筛实际上存在重复的部分,比如数字30,会被质数3和质数5重复筛掉,就会浪费时间,因此我们需要优化算法从而使每个数字只被筛一次,使得时间复杂度降成 线性的时间复杂度。所以就出现了线性筛。时间复杂度O(n)

算法思路k

​ 数字\(x\),其最小质因数\(k\),将小于等于\(k\)的所有质数\(p_i\)乘上数字\(x\),并将\({p_i}*{x}\)的最小质因数标记为\(pi\),质数的最小质因数是本身。

分析

  1. 为什么\({p_i}*{x}\)的最小质因数是\(p_i\)

    \(p_i<=k\)\(p_i\)是比\(x\)的最小质因数还小或者相等的质数,乘起来肯定是\(p_i\)是最小质因数了。因为\(p_i<=k\),所以每个数字只能被筛一次。

  2. 如何保证每一个合数一定会被筛掉?

    每一个合数都能分解成质数的乘积,质数\(p_i\)乘上一个合数实际上也是质数在乘质数,并且这个\(p_i\)还是最小的一个质因子,\({p_i}*{x}\)\(p_i\)\(x\)的乘积可以构成新的合数,因为\(x\)是递增的,并且\(p_i\)是唯一的,因此\({p_i}*{x}\)只会被筛一次。

代码

int p[N];//最小值质因数
int prime[N];//用来存素数集合 
int cnt=0;//目前素数集的个数
for (int i = 2; i <= N; i++) {
	if (p[i] == 0) {//如果这个数字没被之前数字筛到,那么就是质数
		p[i] = i;
		prime[cnt++] = i;//把这个放到质数集里面
	}
	for (int j = 0; j < cnt; j++) {
		if (prime[j] > p[i] || prime[j] * i > N) {//超出范围了 不需要
			break;
		}
		p[prime[j] * i] = prime[j];
	}
}
posted @ 2020-12-03 21:40  Fanxuwei  阅读(332)  评论(0编辑  收藏  举报