筛法

考虑一个经典问题:求不大于 n 的所有素数

Eratosthenes 筛法(埃氏筛)

可能是因为名字太长太难念了所以才叫埃氏筛吧

算法原理

  1. 初始时令列表 \(A = \{ 2,3,...,n \}; \ p = 2\)
  2. 枚举所有 \(p\) 的倍数 (不包括 \(p\)),并在 \(A\) 中删去这些数
  3. \(p\)\(A\) 中的下一个数并跳转至 \((2)\)。如果不存在下一个则结束。
  4. 算法结束时,\(A\) 中剩下的数为不大于 \(n\) 的所有素数。

code

int sieve(int n, bool isprime[], int prime) {
	int tot = 0;
	for (int i = 2; i <= n; i++) isprime[i] = 1;
	for (int i = 2; i <= n; i++) {
		if (isprime[i]) {
			prime[++tot] = i;
			for (int j = i + i; j <= n; j += i)
				isprime[j] = 0;
		}
	}
	return tot;
} 

如何 O(n) 求 1 ∼ n 的素数?

把筛法做到 \(O(n)\),每个合数必须只被筛去一次。
考虑 \(dp\)\(1 ∼ n\) 每个数的最小质因子 \(f[]\)
如果已经知道 \(f[i]\),那么枚举 \(1 ∼ f[i]\) 的所有素数 \(p\),就可以求得 \(f[i·p] = p\)
容易看出每个 \(f[i]\) 只会被求一次
如果枚举至 \(i\) 时还未求出 \(f[i]\),则 \(i\) 不存在小于 \(i\) 的质因子,即 \(i\) 为质数。
这就是传说中的欧拉筛,也叫线性筛

int erlur(int n, int f[], int prime) {
	int tot = 0;
	for (int i = 2; i <= n; i++) {
		if (!f[i]) prime[++tot] = f[i] = i;
		for (int j = 1; j <= tot; j++) {
			int t = i * prime[j];
			if (t > n) break;
			f[t] = prime[j];
			if (f[i] == prime[j]) break;
		}
	}
} 
posted @ 2020-07-04 21:32  Kersen  阅读(255)  评论(0编辑  收藏  举报