[復習]莫比烏斯反演,杜教篩,min_25篩
莫比烏斯反演
做題的時候的常用形式:
實際上還有
證明可以看看這里,只需要把式子帶回去就可以證了。
式子很簡單,做題很有用,技巧很豐富。
主要通過題目來寫這一部分的內容。
- 【BZOJ1101】ZAP
題意:求\(\displaystyle \sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)==d]\)
題解:
令\(\displaystyle f(d)=\sum_{i=1}^a\sum_{j=1}^b[gcd(i,j)==d],g(n)=\sum_{n|d}f(d)\)。
那么通過式子的含義不難知道\(\displaystyle g(d)=\sum_{i=1}^a\sum_{j=1}^b[d|gcd(i,j)]\)。
那么推導就很簡單了
考慮最終這個求和式,如果直接單次\(O(min(a,b)/d)\)的計算,那么復雜度是\(O(Tmin(a,b)/d)\)的,是會\(TLE\)的。
實際上,當\(i\)取\([1,n]\)時,\(n/i\)向下取整的取值只有大約\(2\sqrt n\)個左右,所以對於相同的值完全可以合並在一起算,所以我們只需要處理出\(\mu\)的前綴和即可直接數論分塊計算,把單次復雜度優化到了\(\sqrt {min(a,b)}\)級別。
令\(\displaystyle f(d,n,m)=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]ij,g(n)=\sum_{n|d}f(d)\)
則
其中\(\displaystyle S(n)=\sum_{i=1}^ni=\frac{n(n+1)}{2}\)
那么題目中的式子要求的是\(\displaystyle f(1)=\sum_{i=1}^n\mu(i)g(i)\)。
帶回到式子中去,可以得到:
到了這一步,可以做到\(O(n)\)的復雜度了,提前預處理后面整塊的前綴和,然后數論分塊計算答案即可。
但是如果要復雜度更加優秀的話,我們需要繼續推導。
不難發現最后那一部分是一個積性函數,那么\(\displaystyle T\sum_{i|T}i\mu(i)\),可以在線性時間里面篩出值並算出前綴和,所以對於前半部分數論分塊,可以做到單次詢問\(O(\sqrt n)\)。
考慮這里比前面單詞詢問線性的優化在了哪里,之前那個的確可以做到回答答案是根號級別的,但是因為每次的\(n,m\)的值都不同,導致不得不需要對於每一次不同的詢問做一次前綴和,而后面那個則每次需要預處理的東西都是一樣的,因此只需要全局做一次預處理即可。
想想這個操作的本質,其實就是數論分塊的對象不同而已,因此當有多個和式出現的時候,要考慮清楚到底對於誰進行數論分塊,能夠達到最好的效果。
現在可以來總結一下。
我們仔細想想,這類題目的難點在哪里呢?
首先是推式子,但是這個熟練之后很簡單。注意對於不同的東西數論分塊可以得到不同的復雜度。
其次就是為了數論分塊求函數的前綴和了。其實這個算不上太難,如果數據范圍到了\(1e7\),顯然只能線性篩,那就通過線性篩的本質來考慮,如果當前加入的是一個從未出現過的質因子,那么直接乘積即可,否則的話考慮額外加入一個重復質因子時的貢獻。對於賦初值而言,只需要單獨考慮質數的貢獻就好了。如果數據范圍並沒有到達\(1e7\),如果在\(1e6\)的范圍內,不要一味考慮線性篩,這個復雜度下,調和級數的埃氏篩也是可行的。同時要對於一些積性函數的狄利克雷卷積有所了解,這樣推式子的時候會方便很多。
這里也提供幾個比較常用的式子。
\(1\)表示常數,即\(1(i)=1\)。
\(e\)表示單位元,\(e(i)=[i==1]\)。
\(id\)表示這個數本身,\(id(i)=i\)。
\(\mu,\varphi\)就不說了。
-
\(\displaystyle (1*\mu)(n)=\sum_{d|n}\mu(d)=e\)
證明並不難,\(\mu\)考慮的只有單個質因子,當某個質因子出現超過了\(1\)次\(\mu\)的值就是\(0\)。那么我們假設\(\displaystyle n=\prod_{i=1}^k p_i^{a_i}\)。那么我們真正有用的值只有\(2^k\)個。當\(k>0\)的時候,顯然\(\mu=1\)和\(\mu=-1\)是一一對應的,因此和為\(0\),當\(k=0\)的時候,\(n=1\),此時結果為\(1\)。因此這兩個的狄利克雷卷積就是單位元。 -
\(\displaystyle (\mu*id)(n)=\sum_{d|n}d\mu(\frac{n}{d})=\varphi(n)\)
其實換種寫法就很好證明了,\(\displaystyle \sum_{d|n}\frac{n}{d}\mu(d)\)。
\(\mu\)函數又可以稱為容斥系數,那么這鬼玩意的本質就是\(n\)減去其大於\(1\)的約數的倍數,也就是與\(n\)互質的數的個數,也就是\(\varphi\)。 -
\(\displaystyle (1*\varphi)(n)=\sum_{d|n}\varphi(d)=id(n)=id\)
可以用狄利克雷卷積的方法證明:\(\displaystyle1*\varphi=1*\mu*id=e*id=id\)。 -
\(\displaystyle \sum_{i=1}^n [gcd(i,n)=1]i\)
即小於\(n\)並且與\(n\)互質的數之和。除了莫比烏斯反演可以推之外,還有一個很好的推導方法。假設\(x\)與\(n\)互質,那么\(n-x\)與\(n\)互質,因此所有與\(n\)互質的數可以兩兩配對,且和為\(n\)。因此上述式子等於\(\displaystyle \frac{n\varphi(n)}{2}\)。
杜教篩
求解積性函數前綴和。
假設給定的積性函數為\(f(x)\),設它的前綴和\(\displaystyle S(n)=\sum_{i=1}^n f(i)\)。
顯然不能直接求解我們才會單獨把它拿出來考慮。
既然不能直接求解的話,肯定要找一個什么東西來過度,假裝我們找到了一個積性函數\(g(x)\)。
把兩者卷積起來:
然后考慮求解這個玩意的前綴和:
然后我們驚奇的發現有這么一個式子:
那么假裝我們可以快速的計算\((f*g)\)的前綴和,那么后半部分可以數論分塊+遞歸求解。
這樣一來我們就可以還原出\(S(n)\)了。
所以。。。實際上杜教篩就是一個構造的過程。
那么能夠快速計算前綴和要有多好求呢?比如說我們要求\(\mu\)的前綴和,那么最好可以\(O(1)\)求,而\(\mu*1=e\),\(e\)的前綴和就是\(1\),那就很好辦了。令\(f(x)=\mu(x),g(x)=1\),可以得到
這個東西?遞歸算算就好了。當然了,別少了記憶化。
推式子熟練了就很好了,而構造\(g\)的時候就記住前面講的幾個常用的狄利克雷卷積的式子,往那個上面靠。這里隨便推一道題目可以看看是怎么構造的。
- 【洛谷3768】簡單的數學題
前面的是莫比烏斯反演,推導過程會寫的比較簡單。
考慮怎么求\(f(T)=T^2\varphi(T)\)的前綴和,這個東西顯然是一個積性函數。
發現式子中帶\(\varphi\),所以杜教篩配\(g\)的時候往\(\displaystyle \sum_{d|T}\varphi(T)=T\)上面靠。
因為要往只有\(\varphi\)上靠,所以令\(g(x)=x^2\)
那就很好辦了,\(\displaystyle \sum_{i=1}^n i^3=(1+2+...+n)^2\)可以\(O(1)\)計算,那么直接杜教篩就可以快速計算前綴和了。
那么杜教篩就是一個具有很強的構造性的東西,這也從一些方面上使得其並不是那么的實用。
min_25篩
\(min\_25\)篩用於計算積性函數前綴和\(\displaystyle S(n)=\sum_{i=1}^n f(i)\)。
相比於杜教篩而言,\(min\_25\)篩的題目更加靈活多變
所求的積性函數要滿足兩個條件
- \(f(x)\)在\(x\)為質數的時候要存在一個多項式的表示方法。
- \(f(x^c)\)在\(x\)為質數的時候能夠快速計算。
至於為什么是這兩個條件,與\(min\_25\)篩的過程之間有着密切的聯系。
既然上述的條件中,我們已經把質數單獨分割出來了,那么我們應該明白,\(min\_25\)篩的過程是一個分解過程,即把所有數分成兩類,質數以及合數,當然還有特殊的\(1\)。
這里提前說明幾個東西,底下直接把\(P\)定義為質數集合,\(P_i\)表示的是第\(i\)大的質數。
- 質數部分
令\(g(n,j)\)表示的是,小於等於\(n\)的所有數\(i\)中,其最小質因子\(p\gt P_j\)或者\(i\)本身就是質數的所有的\(i\)的\(f(i)\)之和。
等等,前面不是說了只有當\(i\)是質數的時候才能方便的計算\(f(i)\)嗎?別急,這里我們假裝所有數都是質數,帶入到是質數的式子中一起計算,換句話說,這里就是一個構造過程,不需要管那么多啦QwQ。或者這樣想,如果我們知道了\(g(n,\infty)\),顯然這個東西就是所有質數的和啊QaQ。接下來往下面看吧。
考慮一下這個東西怎么樣才能轉移呢,顯然我們的轉移從\(j-1\)轉移到了\(j\),那么就考慮\(g(n,j-1)\)比\(g(n,j)\)多算了些什么。
多算的部分顯然就是那些最小質因子恰好為\(P_{j}\)的數(別忘了上面那個是大於號),那么最小的一個最小質因子為\(P_{j}\)的數是誰呢?\(P_{j}^2\)。如果\(P_j^2\)比\(n\)都要大了,那么我們什么也沒有減掉,意味着\(g(n,j)=g(n,j-1)\)。
否則的話,想想我們減掉了什么呢?我們先給所有數除掉一個\(P_j\),那么如果剩下的部分的最小質因子還小於等於\(P_j\)的話那么顯然不合法,也就是\(\displaystyle g([\frac{n}{P_j}],j-1)\),但是這樣子減多了,把小於\(P_j\)的質數的貢獻給減掉了,這些質數與\(P_j\)構成的合數的最小質因子小於\(P_j\),顯然是早就被減掉了。那么我們重新把第\(1\)個到第\(j-1\)個質數的貢獻加回來,也就是\(g(P_j-1,j-1)\)。
然后我們要求的是\(g\)的和,我們減去的是\(P_j\)因子的貢獻,而\(f(x)\)為積性函數,所以轉移可以寫成:
前面也說了,\(f(x)\)在\(x\)為質數的情況下可以寫成一個多項式的形式,所以其實這個求\(g\)的本質上可以理解為求\(f(x)=x^k\)的一個過程。同時,每次都是從\(j-1\)轉移到\(j\),仔細思考,這個過程很類似於埃氏篩法,每次篩去了一個質數的所有倍數的貢獻。
那么如果最終要計算出所有質數的貢獻,那么顯然就是\(g(n,\infty)\),事實上我們只需要算到\(\sqrt n\) 以內的所有質數就行了。同時,因為上述轉移的過程中是整除,其實在計算過程中的\(n\)的取值也只有\(2\sqrt n\)個左右,也只需要離散后記錄這些位置就行了。
而\(g\)的初值也就是\(g(n,0)\)自己想想怎么計算吧QwQ。
- 合數部分
知道了質數的貢獻,而目標函數又是積性函數,所以我們只需要用所有的質數拼出所有的合數就可以計算答案了。
令\(S(n,j)\)表示所有最小質因子大於等於\(P_j\)的數\(i\)的\(f(i)\)的和,注意這里和上面\(g\)的描述的區別。
那么計算\(S\)的值的時候顯然是先把質數的貢獻給算上,這一部分的貢獻是\(\displaystyle g(n,|P|)-\sum_{i=1}^{j-1}f(P_j)\),其中\(P\)是小於等於\(\sqrt n\)的質數集合。
接下來考慮合數的貢獻,顯然每個合數都存在一個最小質因子,那么我們來枚舉這個因子,假設為\(P_k,k\geq j\),枚舉其冪,假設為\(e\),那么考慮的就是所有包含了\(P_k^e\)的合數的貢獻。
因為\(f\)是積性函數,所以把這里每次就考慮只包含\(P_k^e\)的貢獻,首先是\(\displaystyle S([\frac{n}{P_k^e}],k+1)\),因為這里並沒有包含\(1\)的貢獻,意味着\(P_k^e\)本身的貢獻沒有計算進來,所以要額外加進來。
所以轉移就可以寫成:
所以底下就來丟幾道題目吧。。。
- 【LOJ#6053】簡單的函數
發現這個東西是\(f(p^k)=p\oplus k\),對於質數而言\(f(p)=p-1\),當然\(2\)比較特殊\(f(2)=p+1=3\),所以我們先把它當成\(p-1\)算,最后再加上\(2\)就好了。
前面也說了,因為在質數上涉及到的是一個多項式計算,所以本質上要求解的就是\(f(p)=p^k\)的形式,那么從這個式子就知道我么要求的是\(k=0\)和\(k=1\)的情況。
設\(g(n,j)\)表示\(k=1\)的情況。即\(f(p)=p\),那么顯然有轉移:
設\(h(n,j)\)表示\(k=0\)的情況,即\(f(p)=1\)時的計算,那么有轉移:
顯然有\(g(n,|p|)-h(n,|p|)\)為所有質數的答案,假設其為\(F(n)\)。
那么設\(S(n,j)\)表示\(\displaystyle \sum_{i=2}^n f(i)\),其中\(i\)的最小質因子大於等於\(P_j\)。
得到轉移:
那么簡單的遞歸處理即可。
講講幾個實現的地方,首先要篩的質數只有\(\sqrt n\)以內的,所以完全可以把他們的\(f\)的前綴和給求出來,這也就是\(g\)和\(S\)中轉移看起來不好算的兩部分的計算方法。其次,計算\(g(n,j)\)的時候,真正有用的\(n\)只有\(2\sqrt n\)個,因為這個過程你可以看成一個數論分塊的過程,因此提前把\(n\)給數論分塊,得到所有有用的\(n\),這樣子可以節約大量空間。第三,發現\(g\)的轉移的中,之和\(j-1\)相關,意味着在開數組的時候只需要開一維,第二維可以滾掉,並且實際上最終\(g\)要用的也只有\(g(n,|P|)\),所以滾掉就好了。最后一個,計算\(S\)的時候不需要記憶化。
這題代碼我重寫了一遍,直接戳LOJ的提交記錄吧。
- 【UOJ#188】sanrd
求\(\displaystyle \sum_{i=l}^r f(i)\)的值,其中\(f(i)\)表示\(i\)的次大質因子。
看起來這里的這個函數與質數無關,並且也不是一個積性函數了,那么怎么辦呢?
首先實際上我們要求的還是這個函數的前綴和,考慮一下\(min\_25\)篩最終求解答案的過程,每次我們枚舉其當前擁有的最小質因子。那么,通過當前計算的\(S(n,j)\)的\(j\),我們可以很容易的知道當前數的上一個質因子是\(P_{j-1}\)。那么如果以\(P_{j-1}\)為質因數為貢獻的話,顯然就是當前剩下的數中質數的個數,這個可以提前用\(min\_25\)的前半部分篩出來。否則以更大的質數為貢獻,那么枚舉當前的最小質因子把它除掉接着遞歸處理即可,注意\(P_k^c\)的這個數的次大質因子為\(P_k\),這里的貢獻是額外算的。
代碼直接戳UOJ記錄
