1. 程式人生 > >歐拉函數學習筆記

歐拉函數學習筆記

溢出 當前 計算公式 指數 case 簡單 += 證明 edi

原作者:liuzibujian
原文:https://blog.csdn.net/liuzibujian/article/details/81086324
本文稍作補充,精細排版。

前言

歐拉函數聽起來很高大上,但其實非常簡單,也是NOIP裏的一個基礎知識,希望大家看完我的博客能有所理解。
數論是數學的一個分支,它只討論正整數的性質,所以以下都是針對正整數進行研究的。

什麽是歐拉函數

歐拉函數是小於\(x\)的整數中與\(x\)互質的數的個數,一般用\(\varphi(x)\)表示。特殊的,\(\varphi (1)=1\)

如何計算歐拉函數

通式: \(\varphi(x)=x \cdot \prod_{i=1}^n{\left(1-\frac{1}{p_i}\right)},\quad\varphi(1)=1\)


其中\(p_1,p_2,\cdots, p_n\)\(x\)的所有質因數,\(x\)是正整數。

那麽,怎麽理解這個公式呢?對於\(x\)的一個質因數\(p_i\),因為\(x\)以內\(p_i\)的倍數是均勻分布的,所以\(x\)以內有\(\frac{1}{p_i}\)的數是\(p_i\)的倍數,那麽有\(1-\frac{1}{p_i}\)的數不是\(p_i\)的倍數。再對於\(p_j\),同理,有\(1-\frac{1}{p_j}\)的數不是\(p_j\)的倍數,所以有\((1-\frac {1}{p_i})*(1-\frac {1}{p_j})\)的數既不是\(p_i\)的倍數,又不是\(p_j\)

的倍數。最後就有\(\prod_{i=1}^n{(1-\frac{1}{p_i})}\)的數與\(x\)互質,個數自然就是\(x\cdot\prod_{i=1}^n{(1-\frac{1}{p_i})}\)

不理解?沒關系,舉個例子。比如\(x=12\),12以內有\(\frac {1}{2}\)的數是2的倍數,那麽有\(1-\frac {1}{2}\)的數不是2的倍數(1,3,5,7,9,11),這6個數裏又有\(\frac {1}{3}\)的數是\(3\)的倍數,只剩下\((1-\frac {1}{2})*(1-\frac{1}{3})\)的數既不是2的倍數,也不是3的倍數(1,5,7,11)。這樣剩下的\(12*(1-\frac{1}{2})*(1-\frac{1}{3})\)

,即4個數與12互質,所以\(\varphi(12)=4\)

積性函數

先介紹一下什麽是積性函數,後面將會用到。
若當\(m\)\(n\)互質時,\(f(m?n)=f(m)?f(n)\),那麽\(f\)是積性函數。
若對任意正整數,都有\(f(m*n)=f(m)*f(n)\)成立,則\(f\)是完全積性函數。

歐拉函數的幾個性質

1. 對於質數\(p\)\(\varphi(p)=p?1\)

因為p是質數,所以1到n-1都與n互質。

2. 若\(p\)為質數,\(x=p^k\),則\(\varphi(x)=p^k-p^{k-1}\)

\(x\)只有一個質因數\(p\),根據公式\(\varphi(x)=x\cdot\prod_{i=1}^n{\left(1-\frac{1}{p_i}\right)}=x\cdot (1-\frac{1}{p})=p^k\cdot\left(1-\frac{1}{p}\right)=p^k-p^{k-1}\)

3. 歐拉函數是積性函數,但不是完全積性函數

\(m,n\)互質,則\(\varphi(m?n)=\varphi(m)?\varphi(n)\)。特殊的,當\(m=2\)\(n\)為奇數時,\(\varphi(2*n)=\varphi(n)\)

\[\begin{aligned} \varphi(m)* \varphi(n) &= m*n * \prod_{i=1}^{a_m}{(1-\frac{1}{p_i})}*\prod_{i=1}^{a_n}{(1-\frac{1}{p_i})} \&= m*n * \prod_{i=1}^{a_m+a_n}{(1-\frac{1}{p_i})} \&= \varphi(m*n) \end{aligned}\]

4. 當\(n>2\)時,\(\varphi(n)\)是偶數

前幾個都可以利用公式證明,這個卻不行。

首先有一個基本事實:若\(n>m,\,\gcd(n,m)=1\),則\(\gcd(n,n-m)=1\)。直白的說,如果與\(n\)互質的數一個是\(m\),那麽還存在另一個數\(n-m\)也與n互質。

(補充:反證法,設\(\gcd(n,n-m)=k \neq 1\),則有\(a,b\in\mathbb{N}^+,\, a>b\)滿足\(n=ak,\,n-m=bk\),得\(m=(a-b)k\),不符合\(\gcd(n,m)=1\)

\(n\)互質的數是成對出現的,所以\(\varphi(n)\)必為偶數。但還要排除\(m=n-m\)的情況:如果\(m=n-m\),即\(n=2?m\),那麽\(n>2\)\(n,m\)必然不互質,與前提相悖,故\(m\neq n-m\)

附上一個較為麻煩的證明

case 1:若\(n\)為質數,根據性質1,\(\varphi(n)=n-1\)必為偶數。
case 2:若\(n\)為合數,則可以寫成\(n=p_1^{k_1}p_2^{k_2}\cdots p_n^{k_n}\)\(p_1,p_2,\cdots, p_n\)\(n\)的質因數,\(k_1,k_2,\cdots,k_n\)為對應得指數),而歐拉函數是積性函數,\(\varphi(n)=\varphi(p_1^{k_1})\varphi(p_2^{k_2})\cdots \varphi(p_n^{k_n})\),暫且只看\(\varphi(p_1^{k_1})\),根據性質2得到\(\varphi(p_1^{k_1})=p_1^{k_1}-p_1^{k_1-1}=(p_1-1)p_1^{k_1-1}\),其中\(p_1-1\)必為偶數,偶數乘以任何數均為偶數,故\(\varphi(n)\)為偶數。

5. 小於\(n\)的數中,與\(n\)互質的數的總和為\(\varphi(n)*n/2\)\(n>1\)

證明這個也要用到上面所說的基本事實。與\(n\)互質的數一個是\(m\),那麽還存在另一個數\(n-m\)也與\(n\)互質。所以與\(n\)互質的數的平均數是\(n/2\),而個數又是\(\varphi(n)\),可以得到這些數的和就是\(\varphi(n)*n/2\)

6. \(n=\sum_{d|n}{\varphi(d)}\),即n的因數(包括1和它自己)的歐拉函數之和等於n

證明1(理性的證明):

這個證明起來有點麻煩。設\(F(n)=\sum_{d|n}{\varphi(d)}\)

(1)如果\(n=1\)\(\varphi(n)=1=n\),滿足\(F(n)=n\)

(2)如果\(n\)是質數,\(\varphi(n)=n\left(1-\frac{1}{n}\right)=n-1\),所以\(\varphi(n)+\varphi(1)=1\),滿足\(F(n)=n\)

(3)如果\(n\)是一個質數\(p\)的冪,即\(n=p^k\),因為\(p^k\)的因數只有\(1,p,p^2,p^3,\cdots,p^k\),根據歐拉函數的性質2(\(\varphi(p^k)=p^k-p^{k-1}\)),代入計算

\(F(p^k)=\varphi(1)+\varphi(p)+\varphi(p^2)+...+\varphi(p^k)=1+(p-1)+(p^2-p)+...+(p^k-p^{k-1})=p^k\)

滿足\(F(n)=n\)

(4)如果\(n\)有多個質因子,即\(n=p_1^{k_1}p_2^{k_2}\cdots p_n^{k_n}\)

(4.1)首先證明\(F(n)\)是個積性函數:設\(m,n\)互質,則要證\(F(m?n)=F(m)?F(n)\)
\[ \begin{aligned} F(m)?F(n) &= \sum_{i|m}{\varphi(i)}*\sum_{j|n}{\varphi(j)} \ &= \varphi(i_1)*\varphi(j_1)+\varphi(i_1)*\varphi(j_2)+...+\varphi(i_1)*\varphi(j_{kn}) \ &\quad +\varphi(i_2)*\varphi(j_1)+\varphi(i_2)*\varphi(j_2)+...+\varphi(i_2)*\varphi(j_{kn}) \ &\quad +\cdots\ &\quad +\varphi(i_{km})*\varphi(j_1)+\varphi(i_{km})*\varphi(j_2)+...+\varphi(i_{km})*\varphi(j_{kn}) \end{aligned} \]
其中\(i_1,i_2,\cdots ,i_{km}\)\(m\)的所有因數,\(j_1,j_2,\cdots,j_{kn}\)\(n\)的所有因數之和.

因為\(m\)\(n\)互質,所以它們的因數也必然全都兩兩互質,而歐拉函數又是個積性函數,即\(\varphi(i_k*j_k)=\varphi(i_k)*\varphi(j_k)\),那麽上式又可以等價於\(\varphi(i_1*j_1)+\varphi(i_1*j_2)+\cdots+\varphi(i_{km}*j_{kn})\)。可以發現,\(i_1*j_1,i_1*j_2,\cdots,i_{km}*j_{kn}\)這些數構成了\(m?n\)的所有因數。那麽這些數的歐拉函數之和就等於\(F(m?n)\),所以\(F(m?n)=F(m)?F(n)\),證得F是一個積性函數。

(4.2)根據(4.1)與(3),\(n=p_1^{k_1}p_2^{k_2}\cdots p_n^{k_n}\)時,\(F(n)=F(p_1^{k_1})*F(p_2^{k_2})*\cdots*F(p_n^{k_n})=p_1^{k_1}p_2^{k_2}\cdots p_n^{k_n}=n\) 成立。

綜上,\(F(n)=n\)對所有的正整數\(n\)成立。

證明2(感性的證明):

以12為例。12的因子有1,2,3,4,6,12。把與這些數互質的數列出來:

1 :1
2 :1
3 :1 2
4 :1 3
6 :1 5
12:1 5 7 11

不妨把這些數作為分母,把與這些數互質的數作為分子,寫成分數形式:

1/1
1/2
1/3 2/3
1/4 3/4
1/6 5/6
1/12 5/12 7/12 11/12

顯然,每一行的數的個數就是該行的分母的歐拉函數值。倘若把這些數都改成以12為分母的數:

12/12
6/12
4/12 8/12
3/12 9/12
2/12 10/12
1/12 5/12 7/12 11/12

可以發現,這些數是以12為分母,1~12為分子的所有數,所以個數為12個。所以與12互質的數的歐拉函數值之和就是12。這樣,命題大概就被證明了吧。

求歐拉函數

埃拉托斯特尼篩求歐拉函數

觀察歐拉函數的公式,\(\varphi(x)=x\prod_{i=1}^n{(1-\frac{1}{p_i})}=x\prod_{i=1}^n{\frac{p_i-1}{p_i}}\)。我們用phi[x]表示\(\varphi(x)\)。可以一開始把phi[x]賦值為\(x\),然後每次找到它的質因數就\(phi[x]=phi[x]/p_i?(p_i?1)\)(先除再乘,避免溢出)。當然,若只要求一個數的歐拉函數,可以從1到sqrt(n)掃一遍,若\(\gcd(i,n)=1\)就更新phi[n]。復雜度為\(O(\log n)\)(代碼就不給了)。那要求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的倍數更新掉
            }
        }
    }
}

歐拉篩求歐拉函數

前提是要懂歐拉篩。每個數被最小的因子篩掉的同時,再進行判斷。i表示當前做到的這個數,prime[j]表示當前做到的質數,那要被篩掉的合數就是i*prime[j]。若prime[j]在這個合數裏只出現一次(i%prime[j]!=0),也就是iprime[j]互質時,則根據歐拉函數的積性函數的性質,phi[i * prime[j]]=phi[i] * phi[prime[j]]。若prime[j]在這個合數裏出現了不止一次(i%prime[j]=0),也就是這個合數的所有質因子都在i裏出現過,那麽根據公式,\(\varphi(i * prime[j])=prime[j] * i * \prod_{k=1}^n{(1-\frac{1}{p_k})} =\varphi(i) *prime[j]\)。復雜度為\(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]];//利用了歐拉函數是個積性函數的性質 
        }
    }
}

總結

有關歐拉函數的性質,只需做個了解,而求歐拉函數的代碼,卻是一定要會寫的。這只是走進數論世界的第一步。

歐拉函數學習筆記