本文包括埃氏筛和线性筛。
埃氏筛
Θ(nloglogn)
复杂度证明需要复变函数知识,从略。
1 2 3 4 5 6 7 8 9
| void prime() { for (int i = 2; i <= N; i++) { if (isp[i]) continue; pri[++cnt] = i; for (int j = i + i; j <= N; j += i) isp[j] = 1; } }
|
线性筛
Θ(n)
保证了每个合数只被最小质因数筛除一次。
1 2 3 4 5 6 7 8 9 10 11
| void prime() { for (int i = 2; i <= N; i++) { if (!isp[i]) pri[++cnt] = i; for (int j = 1; pri[j] * i <= N; j++) { isp[pri[j] * i] = 1; if (i % pri[j] == 0) break; } } }
|
对关键代码的正确性进行证明。设第二层循环枚举到 prij0 时,满足 if
的条件。若此时不终止循环,则对于后续枚举到的 prij1,均有等式
prij1⋅i=prij0ni⋅(prij0n⋅prij1)
此时则造成了对同一合数的重复枚举。又因为对等式右边相乘的两数, gcd(prij0ni,prij0n⋅prij1)=1,所以这两个数的组合必然能在 if
跳出循环前出现,得证。