欧拉函数:给定一个正整数n,在小于等于n的数中,与n互质的数的个数。
关于欧拉函数,有以下几个规律:
1.当n为质数时,euler(n)=n-1.
2.当p与q互质时,euler(p*q)=euler(p)*euler(q).
3.当n等于p^k时,p为质数,euler(n)=p^k-p^(k-1).
对于任意的n,有n=p1^m1*p2^m2*p3^m3……*pk^mk; p1……pk为质数,所以p1^m1……pk^mk都互质
所以euler(n)=euler(p1^m1)*euler(p2^m2)……*euler(pk^mk)
由于规律3,euler(p^k)=(p-1)*p^(k-1)
推理可得:euler(n)=n*(1-1/p1)*(1-1/p2)……*(1-1/pk)
算法实现:利用质因数分解,分解出质因数组合,套用公式即可。
int euler(int n){ int res=n; for(int i=2;i<n;i++){ if(n%i==0){ res=res/i*(i-1); while(n%i==0)n/=i; } } if(n!=1)res=res/n*(n-1); return res; }
如何求解1到n里的每个数的欧拉函数,显然对每个数都跑一遍欧拉函数时非常慢的。
我们可以利用euler(p*q)=euler(p)*euler(q),通过前面已经计算出来的值,推导后面的值。
可以使用线性筛/欧拉筛O(n),在计算n以内的质数的同时,计算n以内的欧拉函数。
const int maxn=100009; int phi[maxn+1]; //phi[i]表示i的欧拉函数 int prime[maxn+1]; //prime[0]用来储存素数个数 void getPrime() { memset(prime,0,sizeof(prime)); for(int i=2;i<=maxn;i++){ if(!prime[i])prime[++prime[0]]=i,phi[i]=i-1; for(int j=1;j<=prime[0]&&prime[j]*i<=maxn;j++){ prime[prime[j]*i]=1; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } phi[i*prime[j]]=phi[i]*phi[prime[j]]; } } }