线性筛
线性筛
Eratosthenes 筛法 (埃氏筛)
时间复杂度$O(n\log\log n)$
具体实现不用多说,就是把每个数的倍数都筛去,剩下的就是质数。
代码略。
欧拉筛
时间复杂度$O(n)$
在埃氏筛中,我们观察到$6$既被$2$筛了一次,又被$3$筛了一次,这样导致时间严重浪费。
欧拉筛就对此进行了优化:每个数只会被它最小的质因子筛一次。
我们先看看代码
线性筛素数
这里的优化就是代码中的
if (i % prime[j] == 0) break;
为什么这样做正确呢?
设$i=k\cdot prime[j]$,那么$i\cdot prime[j+1]=(k\cdot prime[j+1])\cdot prime[j]$,会重复。
故在此处停止循环。
线性筛求$\varphi$和$\mu$
由于$\varphi$和$\mu$均为积性函数,所以可以使用线性筛来解决
当处理到
if (i % prime[j] == 0)
break;
对于$\mu[i]$来说,出现了平方因子,所以$\mu[i]=0$
对于$\varphi[i]$来说,因为其通项公式为
$$\varphi(n)=\prod_{i=1}^{t}(p_i-1)p_i^{k_i-1}=\prod_{i=1}^{t}(1-\frac{1}{pi})p_i^{k_i}=n\prod_{i=1}^{t}(1-\frac{1}{pi})$$
可以发现质因子的出现次数与$$\prod_{i=1}^{t}(1-\frac{1}{pi})$$无关
故直接乘上即可
剩余情况直接根据积性函数的定义来即可
int N, prime[1500005], tot = 0, isp[2000005], phi[2000005], mu[2000005], sump[2000005], summ[2000005]; void prework() { phi[1] = 1, mu[1] = 1; for (int i = 2; i <= N; i++) { if (!isp[i]) { prime[++tot] = i; phi[i] = i - 1; mu[i] = -1; } for (int j = 1; j <= tot && i * prime[j] <= n; j++) { isp[i * prime[j]] = 1; if (i % prime[j] == 0) { mu[i * prime[j]] = 0; phi[i * prime[j]] = phi[i] * prime[j]; break; } else { mu[i * prime[j]] = mu[i] * mu[prime[j]]; phi[i * prime[j]] = phi[i] * phi[prime[j]]; } } } }