一、基本概述
在數論,對正整數n,歐拉函數varphi(n)是少於或等於n的數中與n互質的數的數目。此函數以其首名研究者歐拉命名,它又稱為Euler's totient function、φ函數、歐拉商數等。
二、計算公式

三、基本性質
歐拉函數用希臘字母φ表示,φ(N)表示N的歐拉函數.
對φ(N)的值,我們可以通俗地理解為小於N且與N互質的數的個數(包含1).
歐拉函數的一些性質:
1.對於素數p, φ(p)=p-1,對於對兩個素數p,q φ(pq)=pq-1
歐拉函數是積性函數,但不是完全積性函數.
證明:
函數的積性即:若m,n互質,則φ(mn)=φ(m)φ(n).由“m,n互質”可知m,n無公因數,所以φ(m)φ(n)=m(1-1/p1)(1-1/p2)(1-1/p3)…(1-1/pn)·n(1-1/p1')(1-1/p2')(1-1/p3')…(1-1/pn'),其中p1,p2,p3...pn為m的質因數,p1',p2',p3'...pn'為n的質因數,而m,n無公因數,所以p1,p2,p3...pn,p1',p2',p3'...pn'互不相同,所以p1,p2,p3...pn,p1',p2',p3'...pn'均為mn的質因數且為mn質因數的全集,所以φ(mn)=mn(1-1/p1)(1-1/p2)(1-1/p3)…(1-1/pn)(1-1/p1')(1-1/p2')(1-1/p3')…(1-1/pn'),所以φ(mn)=φ(m)φ(n).
即φ(mn)=φ(n)*φ(m)只在(n,m)=1時成立.
2.對於一個正整數N的素數冪分解N=P1^q1*P2^q2*...*Pn^qn.
φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn).
3.除了N=2,φ(N)都是偶數.
4.設N為正整數,∑φ(d)=N (d|N).
四、求歐拉函數
1、埃拉托斯特尼篩求歐拉函數
觀察歐拉函數的公式,
。我們用phi[x]表示φ(x)。可以一開始把phi[x]賦值為x,然后每次找到它的質因數就
(先除再乘,避免溢出)。當然,若只要求一個數的歐拉函數,可以從1到sqrt(n)掃一遍,若gcd(i,n)=1就更新phi[n] phi[n]phi[n]。復雜度為O(logn)(代碼就不給了)。那要求1~n所有數的歐拉函數呢?可以用埃拉托斯特尼篩的思想,每次找到一個質數,就把它的倍數更新掉。這個復雜度雖然不是O(n),但還是挺快的(據說是O(n*ln ln n),關於證明,可以點這里,雖然我看不懂)。
代碼如下:
void euler(int n) { for (int i=1;i<=n;i++) phi[i]=i; for (int i=2;i<=n;i++) { if (phi[i]==i)//這代表i是質數 { for (int j=i;j<=n;j+=i) { phi[j]=phi[j]/i*(i-1);//把i的倍數更新掉 } } } }
2、歐拉篩求歐拉函數
前提是要懂歐拉篩。每個數被最小的因子篩掉的同時,再進行判斷。i表示當前做到的這個數,prime[j]表示當前做到的質數,那要被篩掉的合數就是i*prime[j]。若prime[j]在這個合數里只出現一次(i%prime[j]!=0),也就是i和prime[j]互質時,則根據歐拉函數的積性函數的性質,phi[i * prime[j]]=phi[i] * phi[prime[j]]。若prime[j]在這個合數里出現了不止一次(i%prime[j]=0),也就是這個合數的所有質因子都在i里出現過,那么根據公式
,復雜度為O(n)。
還是看代碼吧:
void euler(int n) { phi[1]=1;//1要特判 for (int i=2;i<=n;i++) { if (flag[i]==0)//這代表i是質數 { prime[++num]=i; phi[i]=i-1; } for (int j=1;j<=num&&prime[j]*i<=n;j++)//經典的歐拉篩寫法 { flag[i*prime[j]]=1;//先把這個合數標記掉 if (i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的質因子,則根據計算公式,i已經包括i*prime[j]的所有質因子 break;//經典歐拉篩的核心語句,這樣能保證每個數只會被自己最小的因子篩掉一次 } else phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了歐拉函數是個積性函數的性質 } } }
五、例題
http://acm.hdu.edu.cn/showproblem.php?pid=2588
http://poj.org/problem?id=2480
