质数筛法
埃氏筛
1 2 3 4 5
| 2 3 4 5 6 7 8 9
2 3 ~~4~~ 5 ~~6~~ 7 ~~8~~ 9 //筛掉2的倍数
2 3 5 7 ~~9~~ //筛掉3的倍数
复制 |
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <cstdio> #include <cmath>
bool b[100000005];
int main() { int n; scanf("%d",&n); for (int i=2; i <= sqrt(n); i++) { if (!b[i]){ for (int j = i; j <= n/i; j++) { b[i*j]=1; } } }
for (int i = 2; i <= n; i ++) { if (!b[i]){ printf("%d ",i); } } return 0; }
复制 |
11 行处为一个小优化: 的倍数从 开始枚举 (考虑 , 一定会被 的质因数筛去)
举个例子:筛 的倍数时,被打标记的数字分别是
1
| 2*2,2*3,2*4......2*n/2
复制 |
那么我们筛
的倍数时,无优化算法被打标记的数分别是
1
| i*2,i*3,i*4.......i*n/i
复制 |
可以发现,
和
(即
)在枚举
的倍数时已经被打过标记了
其他任意一个
都同理。
版权声明:下方为lyf_018原创文章,遵循 CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_41653433/article/details/88976544
初始时,假设全部都是素数,当找到一个素数时,显然这个素数乘上另外一个数之后都是合数。如果按照埃氏筛做法枚举每个质数的倍数,会造成重复筛除,影响效率。
例如 ,它被 筛了一次,又被 筛了一次,为了解决这个问题,线性筛应运而生:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int mark[MAXN]; int prime[MAXN];
int Prime(int n){ int index = 0; for(int i = 2; i < n; i++){ if(mark[i] == 0) prime[++index] = i; for(int j = 1; j <= index && prime[j] * i < n; j++){ mark[i * prime[j]] = 1; if(i % prime[j] == 0) break; } } return index; }
复制 |
利用了每个合数必有一个最小素因子。每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。
代码中体现在:
1
| if(i%prime[j]==0) break;
复制 |
数组中的素数是递增的,当
能整除
,那么
这个合数肯定也可以被
筛掉,因为
中含有
,
比
小。
接下去的素数同理,所以不用筛下去了。
在满足 这个条件之前以及第一次满足该条件时, 必定是 的最小因子