线性筛质数

暴力

讲解

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

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

代码就不给出了

埃式筛法

讲解

一个很简单的筛法

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

然后就可以做到\(O(n\log\logn)\)筛质数了

代码

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;
		}
	}
}
posted @ 2020-09-03 19:09  皮皮刘  阅读(147)  评论(0编辑  收藏  举报