<演算法筆記02>尤拉函式
阿新 • • 發佈:2021-09-06
演算法介紹
在數論,對正整數n,尤拉函式是小於n的正整數中與n互質的數的數目
\(\phi(n)\)的值為是小於等於n的正整數中與n互質的數的數目
公式
求解尤拉函式公式為
假設\(n\)有\(t\)個質因子,有如下公式
-
公式:
\(\phi(n)=n*(1-\frac{1}{p_1})*(1-\frac{1}{p_2})*...*(1-\frac{1}{p_t})\)
-
證明:
根據容斥定理,假設\(n\)被質因子\(p1,p2\)整除,那麼有\(\frac{n}{p1}\)個數與\(n\)不互質,\(\frac{n}{p_2}\)個數與\(n\)不互質,但是\(\frac{n}{p_1*p_2}\)
性質
- 當\(gcd(a,b)=1\)時,\(\phi(a)*\phi(b)=\phi(ab)\)
- \(a|b\)(\(a\)整除\(b\))時,\(\phi(ab)=\phi(a)*b\)
- \(p\)是質數,\(\phi(p^n)=p^{n-1}*(p-1)\)
性質證明
-
當\(gcd(a,b)=1\)時,\(\phi(a)*\phi(b)=\phi(ab)\)
根據公式,\(a,b\)
-
\(a|b\)(\(a\)整除\(b\))時,\(\phi(ab)=\phi(a)*b\)
根據公式,如果\(a|b\),那麼說明\(b\)擁有的質因子\(a\)一定有,\(\phi(ab)\)展開,b對質因子沒貢獻作用,所以等價於直接乘\(b\)。
-
\(p\)是質數,\(\phi(p^n)=p^{n-1}*(p-1)\),質數的質因子是自己本身,所以直接帶公式即可....
常用板子
-
求解\(\phi(n)\)
思路:試除法求質因子,求的過程中計算即可,時間複雜度\(O(\sqrt{n})\)
int n; cin>>n; ll res=n; for(int i=2;i<=n/i;i++){ if(n%i==0)res=res/i*(i-1); while(n%i==0)n/=i; } if(n>1)res=res/n*(n-1); cout<<res<<endl;
-
求解\(\sum_{i=1}^n\phi(i)\)
思路:可以用埃氏篩法或線性篩法,要運用到上面推導的三個性質。
- 埃氏篩法
/*
埃氏篩法的過程中,我們對質數進行翻倍,那麼每個數字會被自己所有的質因子篩一遍,我們根據這個性質來“順便”求解尤拉函式
*/
#include <iostream>
const int N=1e6+5;
int phi[N];
int main()
{
int n;
cin>>n;
long long res=1;
for(int i=1;i<=n;i++)phi[i]=i;
for(int i=2;i<=n;i++){
if(phi[i]==i){
for(int j=i;j<=n;j+=i){
phi[j]=phi[j]/i*(i-1);
}
}
res+=phi[i];
}
cout<<res;
}
- 線性篩法
/*
利用線性篩法的特點:每個數字有且僅被最小質因子篩一遍
*/
#include <iostream>
const int N=1e6+5;
typedef long long ll;
using namespace std;
int phi[N]={0,1};
int p[N],cnt;
bool book[N];
int main()
{
int n;
cin>>n;
ll res=1;
for(int i=2;i<=n;i++){
if(phi[i]==0)p[++cnt]=i,phi[i]=i-1;//沒被篩到過,表明是質數
for(int j=1;p[j]<=n/i;j++){
if(i%p[j]==0){
phi[i*p[j]]=phi[i]*p[j];//性質2
break;
}
phi[i*p[j]]=phi[i]*phi[p[j]];//性質1 phi[p[j]]在之前以及被計算過
}
res+=phi[i];
}
cout<<res;
}