线性筛卡常技巧
啊?卡常,没有啊?标程只是加了个小优化啊?
于是某人的欧拉筛就在的情况下被卡常死于非命。
素数的判定方法
任何正整数都可以表示为的形式,其中为自然数且,我们讨论每一种:
- :显然有,为合数。
- :可能是素数。
- :,在时为合数。
- :,在时为合数。
- :,为合数。
- :可能是素数。
从上述分类讨论可知:除了以外,所有素数都可以表示为的形式,反之,如果,我们就知道一定不是素数。
常数优化
在刚刚发现的判定的指导下我们就可以对欧拉筛进行常数优化了:
void sieve() {
tot = 0;
for (int i = 1; i <= n; i++) v[i] = false;
for (int i = 2; i <= 5; i++) {
if (!v[i]) prime[++tot] = i;
for (int j = 1; i * prime[j] <= n; j++) {
v[i * prime[j]] = true;
if (i % prime[j] == 0) break;
}
}
for (int k = 6; k <= n; k += 6) {
int i = k + 1;
if (!v[i]) prime[++tot] = i;
for (int j = 1; i * prime[j] <= n; j++) {
v[i * prime[j]] = true;
if (i % prime[j] == 0) break;
}
i += 4;
if (!v[i]) prime[++tot] = i;
for (int j = 1; i * prime[j] <= n; j++) {
v[i * prime[j]] = true;
if (i % prime[j] == 0) break;
}
}
}
可以看到我们手动处理了的素数,然后使用了的结论,直接六个六个筛,但是这么筛会在一定程度上漏筛很多形式的合数,但因为这些形式的合数都是的倍数,在后面筛的循环中不受影响。
这个优化仅限于我们求取所有素数的情况,如果我们依赖于筛的其他副产物,如最小素因子,欧拉函数等,则该算法不正确。
实测中加了这个优化代码能快上2倍!