埃式筛法、欧拉筛法

文章目录

埃氏筛法

埃氏筛法是通过从小到大筛去一个已知素数的倍数进而实现筛选的。
在这里插入图片描述

假如我们想筛掉1~100间的所有合数,步骤如下:
①2是质数,筛掉所有2的倍数
②3是质数,筛掉所有3的倍数
③4不是质数,跳过
④5是质数,筛掉所有5的倍数
⑤6不是质数,跳过
⑥7是质数,筛掉所有7的倍数
⑦8不是质数,跳过
⑧9不是质数,跳过
⑨10不是质数,跳过

总结一下,要想筛掉1~100内的所有合数,我们只需要,找到sqrt(100)=10内的所有质数,即2、3、5、7,把几个数的倍数删掉即可,那么剩下的数就都是质数了。

如果一个数 p 没有被筛掉,说明 2 ~ p-1 的数都没有把它筛掉,也就是 p 不含2 ~ p-1的任何因数,那么 p 一定是个质数。

模板如下:

int st[N];

void get_primes(int n)
{
	for(int i=2; i<=n/i; i++)
	{
		if(!st[i])  //i是质数
		{
			for(int j=i+i; j<=n; j+=i) //筛掉质数 i 的所有倍数 
			st[j]=1;  //标记 j 不是质数 
		}
	}
}

时间复杂度:O(nlogn)


欧拉筛法

我们知道,埃氏筛法是把每个质数的倍数都删掉,比如最上面的那张图片,6和12被质数2筛了一次,又被质数3筛了一次,这是不是有点多余,欧拉筛就是保证每个合数是被最小质因子筛掉的,就如6和12被最小质因子2筛掉的,质数3不需要再筛6和12了。

模板如下:

int st[N],primes[N],cnt;

void get_primes(int n)
{
	for(int i=2; i<=n; i++)
	{
		if(!st[i]) primes[cnt++] = i;  //存质数
		for(int j=0; primes[j] <= n/i; j++) //保证primes[j]*i <= n 
		{
			st[primes[j] * i] = 1;
			if(i % primes[j] == 0) break;  
		}
	}
}

这一步,很重要!if(i % primes[ j ] == 0) break;

扫描二维码关注公众号,回复: 10845183 查看本文章

为什么当 i % primes[j] == 0时跳出循环呢,解释一下:

当满足 if 条件时,i 可以看成 primes[j] * 某个数,而 i * p[j+1] 可以看成 primes[j] * 某个数 * primes[j+1],且 p[j] 一定是< p[j+1] 的,而且,我们知道,欧拉筛是通过合数的最小质因子来筛的,而 i * primes[j+1] 这个合数一定是可以被primes[j] 这个更小的质数筛掉的,不需要通过来primes[j+1]筛掉,因为primes[j+1]不是最小的质因子。

举个例子: i=4时,如果我们在 i%primes[0] ==0 时不退出循环,那就会筛掉3 * 4 这个合数,而12这个合数,我们希望是通过2 * 6 = 12筛掉的,所以需要在i % primes[j] == 0 时就 break。

欧拉筛也称线性筛,因为其时间复杂度是线性的,O(n)
因为欧拉筛相比埃氏筛,减少了重复筛去同一个合数的次数,当然也就比埃氏筛要快啦。

发布了107 篇原创文章 · 获赞 199 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/wmy0217_/article/details/105164461