『歐拉函數與線性篩』
<更新提示>
<第一次更新>
<正文>
歐拉函數
定義
\(\forall\ a,b\in N\),若\(gcd(a,b)=1\),則稱\(a\),\(b\)互質。
對於一個正整數\(n\),我們將\(1-n\)中與\(n\)互質的數的個數稱為歐拉函數,記為\(\phi(n)\)。
求解
若在算數基本定理中,有\(n=p_1^{a_1}*p_2^{a_2}*...*p_k^{a_k}\),則可以得到:
\[\phi(n)=n*\prod_{i=1}^{k}\frac{p_i-1}{p_i}\]
證明:
設\(p\)為\(n\)的一個質因子,則\(1-n\)中\(p\)的倍數有\(p,2p,3p,...,\frac{n}{p}p\),即\(1-n\)中不含有因子\(p\)的數的個數為\(n-\frac{n}{p}\)個。
設\(q\)為\(n\)的另一個質因子,由容斥原理可得\(1-n\)中不含有因子\(p\),\(q\)的數的個數為\(n -\frac{n}{p}- \frac{n}{q}+ \frac{n}{pq}=n(\frac{p-1}{p})(\frac{q-1}{q})\)個。
推廣到\(n\)的每一個質因子,可得\(1-n\)中不與\(n\)含有任何共同質因子的數的個數為\(n*\prod_{i=1}^{k}\frac{p_i-1}{p_i}\)個,即\(\phi(n)=n*\prod_{i=1}^{k}\frac{p_i-1}{p_i}\)。
利用如上公式,我們可以直接在分解質因數的過程中求得一個數的歐拉函數,時間復雜度為\(O(\sqrt n)\)。
\(Code:\)
inline int phi(int x)
{
int ans=x;
for (int i=2;i*i<=x;i++)
{
if (x%i==0)
{
ans=ans/i*(i-1);
while (x%i==0)n/=i;
}
}
if (n>1)ans=ans/n*(n-1);
return ans;
}
性質
\(1.\)對於質數\(p\),有\(\phi(p)=p-1\)
證明:由定義可得。
\(2.\)\(\forall \ n>1\),\(1-n\)中與\(n\)互質的數的和為\(\frac{n}{2}\phi (n)\)
證明:
由於\(gcd(n,x)=gcd(n,n-x)\),所以與\(n\)不互質的數\(n-x,x\)成對出現,且平均值為\(\frac{n}{2}\),因此與\(n\)互質的數的平均值也為\(\frac{n}{2}\),\(n\)互質的數的和即為\(\frac{n}{2}\phi (n)\)。
\(3.\)若\(gcd(a,b)=1\),則\(\phi(ab)=\phi(a)\phi(b)\)
\(4.\)歐拉函數是積性函數,即\(n=\prod p_i^{a_i}\),\(\phi(n)=\prod \phi(p_i^{a_i})\)
\(5.\)對於一個質數\(p\),若有\(p|n,p^2|n\),則\(\phi(n)=\phi(\frac{n}{p})*p\)
\(6.\)對於一個質數\(p\),若有\(p|n,p^2\not | n\),則\(\phi(n)=\phi(\frac{n}{p})*(p-1)\)
證明:
可以由歐拉函數的計算式直接推導得到。
\(7.\)\(\sum_{d|n}\phi(d)=n\)
證明:
設函數\(f(x)=\sum_{d|n}\phi(d)\),則\(f(nm)=\sum_{d|nm}\phi(d)\),若\(n,m\)互質,利用歐拉函數是積性函數可以得到:\[f(nm)=\sum_{d|nm}\phi(d)=\sum_{d_1|n}\sum_{d_2|m}\phi(d_1d_2)=\sum_{d|n}\phi(d)*\sum_{d|m}\phi(d)=f(n)f(m)\]
即函數\(f\)為積性函數。
對於一個質數\(p\),\[f(p^m)=\sum_{d|p^m}\phi(d)=\sum^{m}_{i=0}\phi(p^i)\],由等差數列求和可得\(f(p^m)=p^m\),即可得到\[f(n)=\prod_{i=1}^{m}f(p_i^{a_i})=\prod_{i=1}^{m}p_i^{a_i}=n\]
這些性質在不同的題目中有不同的作用,需要我們註意靈活運用。特別是性質\(6.\),在\(dirichlet\)卷積,\(M?bius\)反演中等內容中也會起到作用。
線性篩求解
對於求解\(1-n\)所有數的歐拉函數,如果直接使用分解質因數法,時間復雜度為\(O(n\sqrt n)\)。
事實上,我們可以利用歐拉函數的性質\(1.\ 5.\ 6.\),再線性篩的求解過程中順帶地求解歐拉函數(線性篩見『素數 Prime判定和線性歐拉篩法 The sieve of Euler』)。
\(Code:\)
inline void eular(void)
{
for (int i=2;i<=n;i++)
{
if (!flag[i])Prime[++cnt]=i,phi[i]=i-1;
for (int j=1;j<=cnt&&i*Prime[j]<=n;j++)
{
flag[ i*Prime[j] ] = true;
if (i%Prime[j]==0)
{
phi[ i*Prime[j] ] = phi[i] * Prime[j];
break;
}
else phi[ i*Prime[j] ] = phi[i] * (Prime[j]-1);
}
}
}
<後記>
感謝\(hzk\) 歐拉函數的介紹(附加歐拉定理和費馬小定理的介紹)。
『歐拉函數與線性篩』