首先是很常用的线性筛代码:
#define N 1000000
int n, cnt, vis[N+5], prime[N+5];
void sieve() {
vis[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!vis[i]) prime[++cnt] = i;
for(int j = 1; j <= cnt && i*prime[j] <= n; ++j) {
vis[i*prime[j]] = 1;
if(i%prime[j]==0) break;
}
}
}
线性筛保证了每个合数只会被它的最小质因子筛掉,所以复杂度是近似(O(n))的。
欧拉函数
定义:对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目(φ(1)=1)。
计算公式:
$phi(x)=xprodlimits_{i=1}^{n}(1-frac{1}{p_i})$
其$p_i$为$x$的质因子。
性质:欧拉函数是积性函数(即$phi(mn)=phi(m)phi(n)$,m,n互质)
我们考虑怎样在线性筛时顺便求出欧拉函数:
1.若$vis[i]=1$,说明$i$是质数,$phi[i]=i-1$
2.若$prime[j]$整除$i$,说明$i*prime[j]$标准分解式中$prime[j]$的次数已经大于$1$了,根据欧拉函数的计算式,不难得出$phi[i*prime[j]]=phi[i]*prime[j]$
3.若$prime[j]$不整除$i$,说明$i$与$prime[j]$互质,又因为$prime[j]$是质数,则$phi[i*prime[j]]=phi[i]*phi[prime[j]]$,进而推出$phi[i*prime[j]]=phi[i]*(prime[j]-1)$
我们按照上式把线性筛改造一下就行了:
```cpp
#define N 1000000
int n, cnt, vis[N+5], prime[N+5], phi[N+5];
void sieve() {
vis[1] = phi[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!vis[i]) prime[++cnt] = i, phi[i] = i-1;
for(int j = 1; j <= cnt && i*prime[j] <= n; ++j) {
vis[i*prime[j]] = 1;
if(i%prime[j]==0) { phi[i*prime[j]] = phi[i]*prime[j]; break; }
phi[i*prime[j]] = phi[i]*phi[prime[j]];
}
}
}
```