求歐拉函數


  在數論,對正整數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 }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM