线性筛质数

暴力

讲解

对于每个数,我们用(O(sqrt n))的时间判断是否是质数

所以时间复杂度是(O(nsqrt n))

代码就不给出了

埃式筛法

讲解

一个很简单的筛法

对于每个质数,将它所有的倍数打上标记,表示不是质数

然后就可以做到(O(nlogn))筛质数了

代码

bool vis[MAXN];
int prime[MAXN],pn;
void sieve(int x)
{
	for(int i = 2;i <= x;++ i)
	{
		if(!vis[i]) 
		{
			prime[++pn] = i;
			for(int j = i*2;j <= x;j += i)
				vis[j] = 1;
		}
	}
}

欧式筛法

讲解

由于埃式筛法每个合数会被所有的质因数筛一遍,所以时间复杂度是(O(nlogn))

但是欧式筛法保证每个合数只会被最小的质因数筛一遍,从而保证了(O(n))的时间复杂度

它是这么实现的(配代码食用更佳):

首先外层循环从(2)开始枚举倍数(i),如果发现当前数字不是质数,加入质数的集合

内层循环枚举已经筛出来的质数(p_j),将(i*p_j)打上标记,如果(i)(p_j)的倍数,直接跳出循环

为什么可以直接跳出循环呢?

(j'>j),所以(p_{j'}>p_j),因为(i)(p_j)的倍数,所以(i*p_{j'})也是(p_j)的倍数,它一定会被(p_j)筛掉

我们希望每个合数被最小的质因数筛掉,而(p_j<p_{j'}),所以可以直接跳出循环

代码

bool vis[MAXN];
int prime[MAXN],pn;
void sieve(int x)
{
	for(int i = 2;i <= x;++ i)
	{
		if(!vis[i]) prime[++pn] = i;
		for(int j = 1;j <= pn && i * prime[j] <= x;++ j)
		{
			vis[i * prime[j]] = 1;
			if(i % prime[j] == 0)//超强优化!
				break;
		}
	}
}
原文地址:https://www.cnblogs.com/PPLPPL/p/13609355.html