欧拉函数学习笔记
原作者: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)\)。
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)\)。
其中\(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。这样,命题大概就被证明了吧。
【证明2·补充】个人认为更为严谨易懂的说明方法:
以12为例。我们把以12为分母,1~12为分子的分数列出,设为集合Q(共12个元素):
Q = {1/12,2/12,3/12,...,11/12,12/12}
如果约分一下会得到:
Q = {1/12,1/6,1/4,1/3,5/12,1/2,7/12,2/3,3/4,5/6,11/12,1/1}
如果再整理一下,会发现:
Q = {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的因子(1,2,3,4,6,12)和与这些数互质的数。
1 :1
2 :1
3 :1 2
4 :1 3
6 :1 5
12:1 5 7 11
于是猜想:Q中12个元素就是12个(因子,与因子互质的数)数对,也是12所有的(因子,与因子互质的数)对。如果可以证明这个猜想,那么就证明了“n的因数(包括1和它自己)的欧拉函数之和等于n”。
现在我们不取12这个特殊值,直接取正整数\(n\),并设集合\(Q\)为以\(n\)为分母、1~\(n\)为分子的数的集合。要证明上述猜想,只需证明下面两个事实:
-
集合\(Q\)中任意一个元素\(q\),可以对应唯一一个(因子,与因子互质的数)数对。
显然,若\(q=a/b\)(已约分),那么\(b\)必为\(n\)的因数,\(a,b\)必然互质。上述事实成立。
-
\(n\)的任意一个(因子,与因子互质的数)数对,可以对应唯一一个集合\(Q\)中元素\(q\)。
设这个数对为\((a,b)\),那么\(a\)为\(n\)的因数且\(a<b\),\(a,b\)互质,设\(n=a*k(k\in \mathbb{N}^+)\),则一定存在唯一元素\(q=b*k/n\)与之对应(分母\(b*k<a*k=n\),当\(a=1\)时例外(\(\varphi(1)=1\)),取等号(\(b=a=1\)),即对应元素\(n/n\))。
由上述两个事实可知,\(Q\)中元素与(因子,与因子互质的数)数对是一一对应的关系(既不存在\(Q\)中元素无法对应数对,也不存在数对无法对应\(Q\)中元素),\(Q\)中元素的个数即为\(n\)的(因子,与因子互质的数)数对的个数,也就是“n的因数(包括1和它自己)的欧拉函数之和等于n”。
求欧拉函数
埃拉托斯特尼筛求欧拉函数
观察欧拉函数的公式,\(\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
),也就是i
和prime[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]];//利用了欧拉函数是个积性函数的性质
}
}
}
总结
有关欧拉函数的性质,只需做个了解,而求欧拉函数的代码,却是一定要会写的。这只是走进数论世界的第一步。