定义:欧拉函数是指小于x的数中,与x互质的数的个数。
特别的,我们知道1的欧拉函数值为0,素数p的欧拉函数值为p-1,当数x不是p素数时,由唯一分解定理我们知道x=p1a1*p2a2*p3a3*……*pnan,其中p1,p2……pn皆为素数,则:phi[x]=x*(p1-1)/p1*(p2-1)/p2……*(pn-1)/pn,证明略。由此我们可以得到一个非线性的求欧拉函数的算法。
void euler() { phi[1]=0; for(int i=2;i<maxn;i++) { if(!phi[i])//素数 for(int j=i;j<maxn;j+=i)//素数去筛它所有的倍数 { if(!phi[j])phi[j]=j;//初始值 phi[j]=phi[j]/i*(i-1);//公式 } } }
其实欧拉函数还有线性的求法,这里我们需要知道:
1:phi[pk]=pk-pk-1,因为与pk不互质的数有p,2p,3p……(pk-1-1)*p,所以phi[pk]=pk-1-(pk-1-1)=pk-pk-1
2:如果i是p的倍数,那么phi[i*p]=p&phi[i],否则phi[i*p]=(p-1)*phi[i].
这样我们就可以在进行素数筛的时候顺便把欧拉函数求出来。
void getphi(int n) { vis[0]=vis[1]=1,phi[1]=0; for(int i=2;i<=n;++i) { if(!vis[i]) { pri[++cnt]=i,phi[i]=i-1; } for(int j=1;j<=cnt&&pri[j]*i<=n;++j) { vis[i*pri[j]]=1; if(i%pri[j]==0) { phi[i*pri[j]]=pri[j]*phi[i]; break; }else phi[i*pri[j]]=(pri[j]-1)*phi[i]; } } }
当然,如果我们只需要求一个数的欧拉函数值,就不用这么麻烦了,直接枚举它的因子,按照公式计算就可以了。
for(int i=2;i<=n;++i) { if(n%i==0)ans=ans/i*(i-1);//因为是从小到大枚举的因子,所以一定都是素因子,这个复杂度比线性的未必小多少,
//但是如果不需要打表的时候写着省事,而且节省空间 while(n%i==0)n/=i; }