参考题目:AcWing 868. 筛质数
埃氏筛:
- 筛掉每个素数的倍数。
- 时间复杂度: O ( n × l o g l o g n ) O(n \times loglogn) O(n×loglogn)
代码:
void get_primes(int n) {
for (int i = 2; i <= n; i ++ ) {
if (!st[i]) { // 如果没有被筛到,说明是素数
primes[cnt ++ ] = i; // 将素数存起来
for (int j = i + i; j <= n; j += i) st[j] = true; // 将该素数的倍数筛掉
}
}
}
线性筛:
- 时间复杂度: O ( n ) O(n) O(n)
- 每个合数被其最小质因子筛掉,因为每个合数都只被筛一次,所以是线性的,称为线性筛。
i % primes[j] == 0
时 break 的原因,保证每个被筛掉的数一定是因为最小质因子而被筛掉的。- 第二层循环中,
primes[j]
为什么一定是primes[j] * i
的最小质因子。理由如下:当i
为合数时,若i % primes[j] != 0
说明i
的最小质因子大于primes[j]
,因为primes[]
是从小到大来枚举的,所以primes[j]
为primes[j] * i
的最小质因子。当i
为质数时,i
首先会进入primes[]
的末尾,而i
的最小质因子为i
,所以primes[j]
为primes[j] * i
的最小质因子。 - 数据要求范围内的合数都会被筛掉。理由如下:设合数
X
的最小质因子为j
,则当i = X / j
时,X
一定会被筛掉。
代码:
void get_primes(int n) {
for (int i = 2; i <= n; i ++ ) {
if (!st[i]) primes[cnt ++ ] = i; // 没被筛掉的为质数
for (int j = 0; primes[j] <= n / i; j ++ ) { //n / i防止溢出
st[primes[j] * i] = true;
if (i % primes[j] == 0) break; // 保证被筛的数最小质因子是primes[j]
}
}
}
参考资料:
https://www.acwing.com/activity/content/code/content/49975/
https://www.acwing.com/video/293/