欧拉函数
定义
欧拉函数是小于x的整数中与x互质的数的个数,一般用 φ(x)φ(x)φ(x) 表示。特殊的,φ(1)=1φ(1)=1φ(1)=1
计算公式
设 xxx 的所有素因子分别为 p1,p2,...pnp_1,p_2,...p_np1,p2,...pn,则
φ(x)=x×∏1n(1−1pi)
φ(x)=x×\prod^{n}_{1}(1-\frac{1}{p_i})
φ(x)=x×1∏n(1−pi1)
用容斥原理证明即可
积性函数
欧拉函数是积性函数,当 gcd(n,m)=1gcd(n,m)=1gcd(n,m)=1 时,φ(n×m)=φ(n)×φ(m)φ(n×m)=φ(n)×φ(m)φ(n×m)=φ(n)×φ(m)
常用性质
- 对于素数 ppp ,φ(p)=p−1,φ(pk)=pk−pk−1φ(p)=p-1,φ(p^k)=p^k-p^{k-1}φ(p)=p−1,φ(pk)=pk−pk−1
- n>2n>2n>2 时,φ(n)φ(n)φ(n) 是偶数,即当 gcd(m,n)=1gcd(m,n)=1gcd(m,n)=1 时,有 gcd(n−m,m)=1gcd(n-m,m)=1gcd(n−m,m)=1,和 nnn 互素的数总是成对出现
- 根据上一条可得,小于 nnn 的数中,与 nnn 互质的数的总和为 φ(n)×n/2(n>1)φ(n)×n / 2 (n>1)φ(n)×n/2(n>1)
- n=∑d∣nφ(d)n=\sum_{d|n}φ(d)n=∑d∣nφ(d) ,即 nnn 的因数(包括1和本身)的欧拉函数之和等于 nnn
实现代码
- 根据公式计算 φ(n)φ(n)φ(n) 直接枚举 nnn 的所有素因子,复杂度和因式分解相同 O(n)O(\sqrt{n})O(n)
int phi(int n){
int m=sqrt(n)+0.5;
int ans=n;
for(int i=2;i<=m;++i){
if(n%i==0){
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
}
if(n>1) ans=ans/n*(n-1);
return ans;
}
- 埃氏筛,找到一个素数,更新它和它的倍数,复杂度 O(n×lnln(n))O(n×lnln(n))O(n×lnln(n))
int phi[maxn];
void init(){
for(int i=1;i<maxn;++i) phi[i]=i;
for(int i=2;i<maxn;++i){
if(phi[i]==i){//代表i是素数
for(int j=i;j<maxn;j+=i){
phi[j]=phi[j]/i*(i-1);
}
}
}
}
- 欧拉筛,每个数被最小的因子筛掉的同时,再进行判断。iii 表示当前做到的这个数,prime[j]prime[j]prime[j] 表示当前做到的质数,那要被筛掉的合数就是 i∗prime[j]i*prime[j]i∗prime[j],若 i % prime[j]≠0i \ \% \ prime[j]\neq0i % prime[j]̸=0,也就是 gcd(i,prime[j])=1gcd(i,prime[j])=1gcd(i,prime[j])=1 互质时,则根据欧拉函数的积性函数的性质,φ(i∗prime[j])=φ(i)×φ(prime[j])φ(i * prime[j])=φ(i) ×φ(prime[j])φ(i∗prime[j])=φ(i)×φ(prime[j])。若 i % prime[j]=0i \ \% \ prime[j]=0i % prime[j]=0,也就是这个合数的所有质因子都在i里出现过,那么根据公式,
φ(i×prime[j])=i×prime[j]×∏k=1n(1−1pk)=prime[j]×φ(i) φ(i×prime[j])=i×prime[j]×\prod_{k=1}^{n}(1-\frac{1}{p_k})=prime[j]×φ(i) φ(i×prime[j])=i×prime[j]×k=1∏n(1−pk1)=prime[j]×φ(i)
即可线性筛选 O(n)O(n)O(n)int prime[maxn],tot; int vis[maxn],phi[maxn]; void init(){ phi[1]=1; for(int i=2;i<maxn;++i){ if(!vis[i]){ prime[tot++]=i; phi[i]=i-1; } for(int j=0;j<tot && 1LL*i*prime[j]<maxn;++j){ vis[i*prime[j]]=1; if(i%prime[j]) phi[i*prime[j]]=phi[i]*phi[prime[j]]; else{ phi[i*prime[j]]=phi[i]*prime[j]; break; } } } }