对于优化后的埃氏筛法:
bool v[N];
void sieve(int n) {
(v, 0, sizeof(v));
memsetfor (int i = 2; i <= n; i++) {
if (v[i]) continue;
for (int j = i; j <= n / i; j++)
[i * j] = true;
v}
}
简单分析一下它的流程,我们发现当 i
不是素数的时候内层循环才会执行,而内层循环执行的次数约为 \(\frac{n}{i} - i\) 次,暗示了其实对于 \(i >
\sqrt{n}\),这个循环也不会被执行,这已经是埃氏筛的一个小优化:即一个数只会被它前半部分的素数筛去,那么总体的时间复杂度就可以表示为:
\[
\begin {aligned}
\sum_{素数 p \le \sqrt {n}} \left (\frac {n}{p} - p\right)
&= \sum_{素数 p \le \sqrt {n}} \frac {n}{p} - \sum_{素数 p \le \sqrt {n}}
p \\
&= n \sum_{素数 p \le \sqrt {n}} \frac {1}{p} - \sum_{素数 p \le
\sqrt {n}} p
\end {aligned}
\] 方便起见我们假设 \(\sqrt{n}\) 为整数,这样就可以避免写 \(\left\lfloor \sqrt{n}
\right\rfloor\),我们先着手估计后半部分,即 \(\sum_{素数 p \le \sqrt {n}}
p\) 的值,通过计算贡献的办法我们得到: \[
\sum_{素数 p \le \sqrt {n}} p = \sqrt {n}\pi\left (\sqrt {n}\right) - \sum_{i
= 2}^{\sqrt {n} - 1}\pi (i)
\] 根据素数定理,我们有 \(\pi(x) \approx
\frac{x}{\ln x}\),那么我们可以得到: \[
\begin{aligned}
\sqrt{n}\pi\left(\sqrt{n}\right) - \sum_{i = 2}^{\sqrt{n} - 1}\pi(i)
&\approx \frac{n}{\ln \sqrt{n}} - \sum_{i = 2}^{\sqrt{n} -
1}\frac{i}{\ln i} \\
&= \frac{2n}{\ln n} - \sum_{i = 2}^{\sqrt{n} - 1}\frac{i}{\ln i} \\
&\approx \frac{2n}{\ln n} - \int_2^{\sqrt{n}}\frac{x}{\ln x}dx \\
&< \frac{2n}{\ln n} - \frac{n}{\ln n} \\
&= O\left(\frac{n}{\ln n}\right)
\end{aligned}
\] 对于前半部分,我们有 Mertens
Theorem 指出: \[
\lim_{n \to \infty} \left (\sum_{素数 p \le n}\frac {1}{p} - \ln\ln n - M
\right) = 0
\] 其中 \(M \approx
0.2614972128\) 为 Meissel-Mertens’ Constant。
这告诉我们前半部分的复杂度是 \(O\left(n\ln\ln\sqrt{n}\right) = O (n\ln\ln n)\) 的,因此合并起来,整个算法的复杂度为 \(O\left(n\ln\ln n - \frac{n}{\ln n}\right) = O(n \ln\ln n)\),和优化前的复杂度一致。