【複習】尤拉函式
阿新 • • 發佈:2018-12-02
首先讓我們來複習以下尤拉函式的概念。
- 寫作\(phi(i)\),表示小於\(i\)的與\(i\)互質的數的個數
- 特殊的,\(phi(1)=1\);
根據定義我們可以得到其推導方法。
- 對於任意的\(i∈[2,INF]\),\(i\)都可以被拆分為\(p1^{c1}*p2^{c2}*...pn^{cn}\)的形式,其中\(pi\)表示素數,而\(ci\)表示素數的次數,即把一個數拆成素數乘積的形式。
- 所以利用容斥原理,我們可得\(phi(i)\)的推導:\(phi(i)=N(1-1/p1)...(1-1/pn)\);
它有一些很優秀的性質:
- \(phi\)是積性函式。對於任意滿足\(gcd(a,b)=1\)
- 若\(p|n\)且\(p^2|n\),則有\(phi(n)=phi(n/p)*p\)
- 證明:若滿足以上條件,則n和n/p的素陣列成相同,不同的只有次數。根據定義式,可以得到\(phi(n)=phi(n/p)*p\).
- 若\(p|n\)且\(p^2\)不被\(n\)整除,則有\(phi(n)=phi(n/p)*(p-1)\)
- 證明:若滿足\(p|n\)且\(p^2\)不被\(n\)整除,則\(n\)和\(n/p\)互質。滿足\(phi(n)=phi(n/p)*phi(p)=phi(n)=phi(n/p)*(p-1)\)
- 證明:若滿足\(p|n\)且\(p^2\)不被\(n\)整除,則\(n\)和\(n/p\)互質。滿足\(phi(n)=phi(n/p)*phi(p)=phi(n)=phi(n/p)*(p-1)\)
那麼關鍵來了:我們要利用這些性質求解尤拉函式。
利用定義式,我們可以很容易想到常規推導:
for(register int i=1;i<=n;++i)phi[i]=i;//先記為其本身 for(register int i=2;i<=n;++i){ if(phi[i]==i){//質數 for(register int j=i;j<=n;j+=i){//處理後面的每一個i的倍數 phi[j]=phi[j]/i*(i-1);//利用定義式計算非積性求解情況 } } } }
這個是建立在埃氏篩基礎上的尤拉函式求法,複雜度是O(nlogn),足以水過P2158 40000 的資料範圍。但是如果資料更大的話,這種演算法很顯然是不優秀的,我們就要考慮更快的演算法,於是便想到了同一個人名字命名的尤拉篩。(尤拉全家桶.jpg)
首先先考慮簡單的尤拉篩求素數集。
vis[1]=1;//vis記錄素數情況,0為素數
for(register int i=2;i<=n;++i){
if(!vis[i])prime[++tot]=i;//素數
for(register int j=1;j<=tot&&i*prime[j]<=n;++j){
vis[i*prime[j]]=1;//合數標為1
if(i%prime[j]==0)break;//j以後的都可以由更小的素數篩得
//如i*prime[j+1]中i本身可以被分解為比prime[j+1]更小的質數。
}
}
同理,很容易就可以想到怎麼對尤拉函式求解了。
for(register int i=1;i<=n;++i)phi[i]=i;
for(register int i=2;i<=n;++i){
if(phi[i]==i){//i為質數
prime[++cnt]=i;//記錄這個數位質數,最小質因子是它自己
phi[i]=i-1;
}
for(register int j=1;j<=cnt&&i*prime[j]<=n;++j){//不超出n的範圍
if(i%prime[j]!=0){
phi[i*prime[j]]=phi[i]*(prime[j]-1);
//如果i%prime[j]!=0,則i*prime[j]和prime[j]互質
}else{
phi[i*prime[j]]=phi[i]*(prime[j]);
break;
}
}
}
就是這樣~
什麼時候會用到尤拉函式呢?通常我們要把它從複雜的模型裡提取出來。例如[P2158 SDOI2008]儀仗隊這個題目,就需要我們想到,對於任意一個首次出現的斜率,其gcd(x,y)一定為1即滿足互質。認真思考後就會發現完全就是一個尤拉函式求和啦~
\(UPD\):關於尤拉篩的那個\(break\)作用的考慮。
毫不誇張的說,尤拉篩中的那個\(break\)是整個演算法中最精華最讓人讚歎的地方。下面我們來考慮一下這種情況:
- \(prime[ ]\)中儲存了所有的素數
- 在尤拉篩中,一旦出現\(i\%prime[j]==0\),就在進行完本次運算後停止。
- 原因:既然已經有\(i\%prime[j]=0\),那麼\(prime[j]\)就是\(i\)的本身組成。在繼續往後找的過程中,\(prime[j]\)只會越來越大。為了符合只讓\(i\)被其最小質因子篩掉一次的條件,我們在做完這次迴圈後就\(break\).