- chjshen 的博客
数学-数论之素数筛法
- 2023-6-1 7:30:21 @
素数筛法
1、埃氏筛法
根据质数的定义,能够被质数整除的数,肯定都是合数。
从小到大遍历每个数x,我们假设这个数是质数,把x的倍数都筛选掉,剩下的就是质数。
模拟筛法过程:
i: | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
2: | 2 |
3 | 4 |
5 | 6 |
7 | 8 |
9 | 10 |
3: | 2 | 3 |
- | - | - | 9 |
- | ||
... |
此算法用到了双重循环,但由于内层循环的步长为i,时间复杂度可看成O(nloglogn)。
for(int i=2; i<=n; i++) {
if (isPrime[i]) {//不是合数,也就是质数
primes.push_back(i);
for(int j=2*i; j<=n ; j=j+i)
isPrime[j] = false;
}
}
2、欧拉筛法
在筛法模拟里会看到存在大量的重复筛,比如6即被2筛掉、也被3筛掉, 如果每个合数都只被一个数筛掉,那么这个算法显然就是O(n)的算法,即线性筛法。
数学描述
:每个数都只被它的最小质因子筛掉。
算法描述
:
- 对每个数a,将a之前的质数乘以a筛为合数。
- 如果某个质数是a的因子,则停止(后面的不要筛了)
对于某个数a,假设已经找到m个质数:p、p1、...pm <= a, 计划将 a 和 这些质数的乘积都筛掉。
但如果a存在一个质因子,假设为px,即 a = px * t 那么对于px到pm之间的任何质数p,都有 a * p = px * (t * p) 也就是说后面肯定会有一个比a大的数b = (t*p),也会筛掉 b * px = a * p
所以,这里就不需要筛这些质数(大于px的质数),可以直接跳过。
模拟筛法过程:
i | 质数 | 筛 |
---|---|---|
2 | 2 |
4 |
3 | 2, 3 |
6, 9 |
4 | 2 ,3 |
8 |
5 | 2,3,5 |
10, 15, 25 |
6 | 2 ,3,5 |
12 |
7 | 2,3,5,7 |
14,21,35,49 |
8 |
2 ,3,5,7 |
16 |
9 |
2,3 ,5,7 |
18,27 |
... |
注意上面的8和9,只需要筛到其质因子乘以该数为止。
由于每个数都只有其最小质因子乘以某个a筛掉,所以这个算法为O(n)。
for(int i=2; i<=n; i++) {
if(isPrime[i])
primes.push_back(i);
for(int j=0; j<primes.size(); j++) {
int p = primes[j];
if(i * p > n) break;
isPrime[i * p] = false;
if(i%p == 0) break;
}
}