单个筛欧拉函数由欧拉函数公式直接在给n分解质因数时连乘就好
代码
int phi(int n) { int res=n,a=n; for(int i=2;i*i<=a;i++) { if(a%i==0) { res=res/i*(i-1);//先除后乘防止溢出 while(a%i==0) a/=i; } } if(a>1) res=res/a*(a-1); return res; }
先说一个近似线性筛的筛法
void Euler() { phi[1]=1; for(int i=2;i<M;i++) if(!phi[i])//没有被筛过说明是质数 for(int k=i;k<M;k+=i) { if(!phi[k]) phi[k]=k; phi[j]=phi[j]/i*(i-1);//欧拉函数公式的实现 } return ; }
线性筛欧拉函数建立在线性筛素数的基础之上
重要性质:若i%p=0,p是素数,那么φ(i*p)=φ(i)*p,若i%p!=0,p是素数,那么φ(i*p)=φ(i)*(p-1)
证明(该证明可能存在错误):当i%p=0时,若GCD(a,b)=1,则GCD(a+b,b)=1,由此可以得出,将φ(i)中的数每个加i,则会得到另外φ(i)个数,若以此类推,累加(p-1)次,则一共有p*φ(i)个数与i互质,因为p是i的质因子,所以与i互质的数必定与i*p互质,所以φ(i*p)=φ(i)*p;当i%p!=0时,发现i,p互质,且p为素数,所以φ(p)等于p-1,由积性函数性质可得φ(i*p)=φ(i)*φ(p)=φ(i)*(p-1)
代码
void getphi() { int vis[M],phi[M],pri[M],tot; for(int i=2;i<=n;i++) { if(!vis[i])//先判断i是不是素数 { pri[++tot]=i; phi[i]=i-1;//当 i 是素数时小于i的所有大于零的数都和i互素 } for(int k=1;k<=tot;k++) { if(i*pri[k]>M) break; vis[i*pri[k]]=1;//按照筛素数,筛掉i的倍数 if(i%pri[k]==0)//如果有一个质数是i的因子,那么phi(i*pri[k])=phi(i)*pri[k] { phi[i*pri[k]]=phi[i]*pri[k];break; } else phi[i*pri[k]]=phi[i]*(phi[pri[k]]); //利用了欧拉函数的积性,两个数互质,那么phi(i*k)=phi(i)*phi(pri[k]) } } }