埃氏筛法和欧拉筛法

埃氏筛的基本思想是先筛去一个素数的所有倍数。

假如n = 1000  要筛去 2 ~ 1000 中的所有合数,因为一个素数的倍数一定是合数,所以我们可以筛去2的所有倍数,3的所有倍数

直到筛去所有合数.

#include <stdio.h>
#include <cstring> 
#include <iostream>
using namespace std;
typedef unsigned long long ull;
const int MAXN = 1e7; 
int np[MAXN];
int p[MAXN] = {0};
void eratosthenes(){
	memset(np, 0, sizeof np);
	np[0] = np[1] = 1;
	for(int i = 2; i*i<= MAXN; i++) // 因为从小到大筛,而且筛去了所有的倍数,所以i ~ i^(i-1)都已近被筛过了,比如i = 9,2*9 3*9 4*9 5*9...都已近被筛过了
		if(!np[i]){
			for(int j = i*i; j <= MAXN; j += i)
				np[j] = 1;
		} 
	return ;
}

虽然埃氏筛经过优化后时间复杂度降低了很多,但还是会对同一个合数进行多次筛选,

比如 24   当 i = 2 时, 24会被筛去,   当 i = 3 时 24又会被筛去一次,

这就造成了重复操作,

欧拉筛就避免了这种重复操作,从而降低了时间复杂度。

欧拉筛的思想是对于一个合数,只用其最小的质因数去筛除它。

void ola(){
	memset(np, 0, sizeof np);
	memset(p, 0, sizeof p);
	int j = 0;
	np[0] = np[1] = 1;
	for(int i = 2; i <= MAXN; i++){
		if(!np[i]) p[++j] = i;
		for(int k = 1; k <= j && i * p[k] <= MAXN ; k++){
			np[i*p[k]] = 1;
			if(i%p[k]==0) break;// 如果i是p[k]的倍数,那么在继续筛的话,就会造成重复操作
		}
	}
}

比如  24  我们只用2去筛除24,而不用 3。当 i = 8 时, 8 * 2  = 16  此时16被筛去, 8 % 2 == 0,退出循环,因为8是2的倍数,如果继续筛下去  8 * 3 = 24 即 2 * 4 * 3 = 24, 即提前筛去了24,而24只能被2筛去,现在却被3筛去了,就造成了重复操作,

所以当 i % p[k] == 0 时, 就退出循环。

发布了52 篇原创文章 · 获赞 114 · 访问量 6008

猜你喜欢

转载自blog.csdn.net/GD_ONE/article/details/101925845