线性筛素数(欧拉筛)

笑着哭i 提交于 2019-12-18 03:19:44

欧拉筛是O(n)复杂度的筛素数算法,1秒内埃筛能处理1e6的数据,而1e7的数据就必须用欧拉筛了。

埃筛的基本思想是:素数的倍数一定是合数。
欧拉筛基本思想是:任何数与素数的乘积一定是合数

算法概述:
遍历[2, n]的所有数i,内层循环遍历已经找到的素数prime[j],将i * prime[j] 标记为合数。
内层循环的最后,检查如果prime[j]i的最小质因子,则退出到外层循环,因为prime[j+1] * i肯定已经被筛过了。

代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e7 + 5;
int isPrime[MAXN]; // isPrime[i] 表示i是否素数
int prime[MAXN]; // 按顺序存素数
int cnt = 0; // 素数个数

// 找出n以内的全部(cnt个)素数
void euler(int n) {	
	memset(isPrime, 1, sizeof(isPrime)); // 默认全是素数
	cnt = isPrime[0] = isPrime[1] = 0; // 素数个数清零,标记0和1不是素数

	// 已知 [2, n] 之间的每一个数 i 与任意素数的乘积一定是合数,
	// 遍历已找到全部素数 prime[j],将 i * prime[j] 标记为合数
	for (int i = 2; i <= n; i++) {
		if (isPrime[i]) prime[cnt++] = i; // 找到素数		
		for (int j = 0; j < cnt; j++) { // 遍历已找到的素数
			if (i * prime[j] > n) break; // 越界跳出
			isPrime[i * prime[j]] = 0; // 标记合数

			// 避免重复筛除的关键代码
			// 当找到i的最小质因子 prime[j] 时,退出循环
			if (i % prime[j] == 0) break;
		}
	}
}

int main() {
	int n; cin >> n;
	euler(n);
	// for (int i = 0; i < cnt; ++i) cout << prime[i] << endl; // 打印素数
	cout << "cnt:" << cnt << endl;
	return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!