在數論,對正整數n,歐拉函數是少於或等於n的數中與n互質的數的數目。此函數以其首名研究者歐拉命名,它又稱為Euler's totient function、φ函數、歐拉商數等。 例如φ(8)=4,因為1,3,5,7均和8互質。 從歐拉函數引伸出來在環論方面的事實和拉格朗日定理構成了歐拉定理的證明。
φ函數的值 通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn為x的所有質因數,x是不為0的整數。φ(1)=1(唯一和1互質的數(小於等於1)就是1本身)。 (注意:每種質因數只一個。比如12=2*2*3那么φ(12)=12*(1-1/2)*(1-1/3)=4若n是質數p的k次冪,φ(n)=p^k-p^(k-1)=(p-1)p^(k-1),因為除了p的倍數外,其他數都跟n互質。設n為正整數,以 φ(n)表示不超過n且與n互素的正整數的個數,稱為n的歐拉函數值,這里函數φ:N→N,n→φ(n)稱為歐拉函數。歐拉函數是積性函數——若m,n互質,φ(mn)=φ(m)φ(n)。特殊性質:當n為奇數時,φ(2n)=φ(n), 證明與上述類似。
求1~N之間的歐拉函數值O(nloglogn)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 LL N; 5 LL Phi[5000000]; 6 inline void get_Phi(){ 7 for(int i=2;i<=N;i++) Phi[i]=0; 8 Phi[1]=1; 9 for(int i=2;i<=N;i++){ 10 if(!Phi[i]){ 11 for(int j=i;j<=N;j+=i){ 12 if(!Phi[j]) Phi[j]=j; 13 Phi[j]=Phi[j]/i*(i-1); 14 } 15 } 16 } 17 } 18 19 int main(){ 20 scanf("%d",&N); 21 get_Phi(); 22 for(int i=1;i<=N;i++){ 23 cout<<Phi[i]<<" "; 24 if(i%10==0){ 25 cout<<endl; 26 } 27 } 28 return 0; 29 }
但是這個復雜度還不夠優秀,網上有O(n)的篩法:
1 /*線性篩O(n)時間復雜度內篩出maxn內歐拉函數值*/ 2 int m[maxn],phi[maxn],p[maxn],pt;//m[i]是i的最小素因數,p是素數,pt是素數個數 3 4 int make(){ 5 phi[1]=1; 6 int N=maxn; 7 int k; 8 phi[1]=1; 9 for(int i=2;i<N;i++){ 10 if(!m[i])//i是素數 11 p[pt++]=m[i]=i,phi[i]=i-1; 12 for(int j=0;j<pt&&(k=p[j]*i)<N;j++) 13 { 14 m[k]=p[j]; 15 if(m[i]==p[j])//為了保證以后的數不被再篩,要break 16 { 17 phi[k]=phi[i]*p[j]; 18 /*這里的phi[k]與phi[i]后面的∏(p[i]-1)/p[i]都一樣(m[i]==p[j]) 19 只差一個p[j],就可以保證∏(p[i]-1)/p[i]前面也一樣了*/ 20 break; 21 } 22 else 23 phi[k]=phi[i]*(p[j]-1);//積性函數性質,f(i*k)=f(i)*f(k) 24 } 25 } 26 }
還可以單獨求歐拉函數的O(sqrt(n)):
1 int euler_Phi(int n){ 2 int m=(int)sqrt(n+0.5); 3 int ans=n; 4 for(int i=2;i<=m;i++){ 5 if(n%i==0){ 6 ans=ans/i*(i-1); 7 while(n%i==0) n/=i; 8 } 9 } 10 if(n>1) ans=ans/n*(n-1); 11 return ans; 12 }