首先是很常用的线性筛代码:
#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)。
计算公式:
其 \(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)\)
我们按照上式把线性筛改造一下就行了:
#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]];
}
}
}