素数筛法总结

素数筛法

一、定义

素数指质数,指在大于 1 的自然数中,除了 1 和它本身以外不再有其他因数的自然数;

二、唯一分解定理

唯一分解定理又称为算术基本定理,可描述为,

任何一个大于 1 的自然数 N N N ,如果 N N N 不为质数,那么 N N N 可以唯一分解成有限个质数的乘积,

N = p 1 a 1 ∗ p 2 a 2 ∗ p 3 a 3 . . . . . . p n a n N = p_1^{a_1} * p_2^{a_2} * p_3^{a_3} ...... p_n^{a_n} N=p1a1p2a2p3a3......pnan

这里 p 1 < p 2 < p 3 < . . . < p n p_1 < p_2 < p_3 < ... < p_n p1<p2<p3<...<pn 均为质数,其中指数 a i a_i ai 为正整数,这样的分解称为 N N N 的标准分解式;

三、埃氏筛法

1. 说明

素数筛法,是一种快速筛出 2 ∼ n 2 \sim n 2n 中之间所有素数的方法。朴素的筛法叫做埃氏筛 (The Sieve of Eratosthenes,埃拉托色尼筛) ;

其核心思想为,遍历到质数时,将其的倍数筛掉;

2. 过程

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

从前向后看,找到第一个未被划掉的数为 2,为质数,把 2 的倍数 (不包括 2 ) 删除,即删除 4, 6, 8, 10, 12, 14, 16;

2 3 5 7 9 11 13 15

下一个未被划掉的数是 3,为质数,把 3 的倍数相除,即删除 6, 9, 12, 15 (注意 6 和 12 虽然为 3 的倍数,但是它是被 2 筛除的) ;

2 3 5 7 11 13

下一个未被划掉的数是 5,但是 5 已经超过 16 \sqrt{16} 16 了,所以遍历结束,剩下未被划掉的数都是素数:

2 3 5 7 11 13

3. 关键代码

bool f[MAXN];//f用来标记i是否为素数,0为素数,1为合数;
void prime(int n) {
    for (int i = 2; i * i <= n; i++) {
        if (!f[i]) {
            for (int j = i * i; j <= n; j += i) {
                f[j] = 1;
            }
        }
    }
}

4. 问题

埃氏筛法在筛数时会筛到同一个数;

四、欧拉筛法

1. 说明

欧拉筛,也叫线性筛,可以在 O ( n ) O(n) O(n) 时间内完成对 2 ∼ n 2 \sim n 2n 的筛选;

其核心思想为,让每一个合数被其最小质因数筛到;

2. 过程

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

质数表如下,

从头到尾遍历,第一个数是 2 ,未被划掉,把它放进质数表;

然后用 2 去乘质数表里的每一个数并删除,这里只删除 4 ;

2 3 5 6 7 8 9 10 11 12 13 14 15 16

质数表如下,

2

下一个是 3,加入质数表划掉 6,9 ;

2 3 5 7 8 10 11 12 13 14 15 16

质数表如下,

2 3

下一个数是 4 (删除的也要遍历,只是不加入质数表),先删除 8,但不删除 12,因为 12 = 2 ∗ 6 12 = 2 * 6 12=26 应该由它的最小质因数 2 筛掉,而不是 3 ;

2 3 5 7 10 11 12 13 14 15 16

质数表如下,

2 3

实际上,对于 x x x ,遍历到质数表中的 P P P ,且发现 p ∣ x p|x px 时,就应当停止遍历质数表;

证明如下,

x = p ∗ r ( r ≥ p ) x = p * r (r \geq p) x=pr(rp) p p p 本身是 x x x 的最小质因数,则对于 ∀ p ′ > p \forall p' > p p>p ,有 p ′ x = p p ′ r = ( p p ′ ) r p'x = pp'r = (pp')r px=ppr=(pp)r ,则说明 p ′ x p'x px 的最小质因数不是 p ′ p' p ,而是 p p p 所以不应该在此删除它;

下一个是 5,加入质数表,删除 10,15 ;

2 3 5 7 11 13 14 16

质数表如下,

2 3 5

3. 关键代码

int prime[MAXN];//用来存放质数表
bool f[MAXN];//f用来标记i是否为素数,0为素数,1为合数;
void Prime(int n) {
    for (int i = 2; i <= n; i++) {
		if (!f[i]) {
			prime[++cnt] = i;
		}
		for (int j = 1; j <= cnt && i * prime[j] <= n; j++) {
			f[i * prime[j]] = 1;
			if (i % prime[j] == 0) break;
		}
	}
}

你可能感兴趣的:(数学,素数筛)