[複習]莫比烏斯反演,杜教篩,min_25篩

[複習]莫比烏斯反演,杜教篩,min_25篩

莫比烏斯反演

作題的時候的經常使用形式:
\[\begin{aligned}g(n)&=\sum_{n|d}f(d)\\f(n)&=\sum_{n|d}\mu(\frac{d}{n})g(d)\end{aligned}\]
實際上還有
\[\begin{aligned}g(n)&=\sum_{d|n}f(d)\\f(n)&=\sum_{d|n}\mu(\frac{n}{d})g(d)\end{aligned}\]
證實能夠看看這裏,只須要把式子帶回去就能夠證了。
式子很簡單,作題頗有用,技巧很豐富。html

主要經過題目來寫這一部分的內容。數組

  • 【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)]\)
    那麼推導就很簡單了
    \[ \begin{aligned} g(d)&=\sum_{i=1}^a\sum_{j=1}^b[d|gcd(i,j)]\\ &=\sum_{i=1}^{a/d}\sum_{j=1}^{b/d} [1|gcd(i,j)]\\ &= \lceil \frac{a}{d} \rceil* \lceil \frac{b}{d} \rceil\\ f(d)&=\sum_{d|i}\mu(\frac{i}{d})g(i)\\ &=\sum_{d|i}\mu(\frac{i}{d})\lceil \frac{a}{i} \rceil* \lceil \frac{b}{i} \rceil\\ &=\sum_{i=1}^{min(a,b)/d}\mu(i)\lceil \frac{a/d}{i} \rceil* \lceil \frac{b/d}{i} \rceil\\ \end{aligned}\\ \]
    考慮最終這個求和式,若是直接單次\(O(min(a,b)/d)\)的計算,那麼複雜度是\(O(Tmin(a,b)/d)\)的,是會\(TLE\)的。
    實際上,當\(i\)\([1,n]\)時,\(n/i\)向下取整的取值只有大約\(2\sqrt n\)個左右,因此對於相同的值徹底能夠合併在一塊兒算,因此咱們只須要處理出\(\mu\)的前綴和便可直接數論分塊計算,把單次複雜度優化到了\(\sqrt {min(a,b)}\)級別。函數

  • 【BZOJ2154】Crash的數字表格/【BZOJ2693】jzptab
    \[\begin{aligned} Ans&=\sum_{i=1}^n\sum_{j=1}^m lcm(i,j)\\ &=\sum_{i=1}^n\sum_{j=1}^m \frac{ij}{gcd(i,j)}\\ &=\sum_{d=1}^n\frac{1}{d}\sum_{i=1}^n\sum_{j=1}^m [gcd(i,j)=d]ij\\ &=\sum_{d=1}^nd\sum_{i=1}^{n/d}\sum_{j=1}^{m/d} [gcd(i,j)=1]ij \end{aligned}\]
    \(\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)\)

    \[\begin{aligned} g(d)&=\sum_{i=1}^n\sum_{j=1}^m[d|gcd(i,j)]ij\\ &=d^2\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}ij\\ &=d^2 S([\frac{n}{d}])S([\frac{m}{d}]) \end{aligned}\]
    其中\(\displaystyle S(n)=\sum_{i=1}^ni=\frac{n(n+1)}{2}\)
    那麼題目中的式子要求的是\(\displaystyle f(1)=\sum_{i=1}^n\mu(i)g(i)\)
    帶回到式子中去,能夠獲得:
    \[\begin{aligned} Ans&=\sum_{d=1}^nd\sum_{i=1}^{n/d}\sum_{j=1}^{m/d} [gcd(i,j)=1]ij\\ &=\sum_{d=1}^nd\sum_{i=1}^{n/d}\mu(i)i^2S([\frac{n}{id}])S([\frac{m}{id}]) \end{aligned}\]
    到了這一步,能夠作到\(O(n)\)的複雜度了,提早預處理後面整塊的前綴和,而後數論分塊計算答案便可。
    可是若是要複雜度更加優秀的話,咱們須要繼續推導。
    \[\begin{aligned} Ans&=\sum_{d=1}^nd\sum_{i=1}^{n/d}\mu(i)i^2S([\frac{n}{id}])S([\frac{m}{id}])\\ &=\sum_{T=1}^nS([\frac{n}{T}])S([\frac{m}{T}])\sum_{d|T,id=T}d\mu(i)i^2\\ &=\sum_{T=1}^nS([\frac{n}{T}])S([\frac{m}{T}])\sum_{i|T}\frac{T}{i}\mu(i)i^2\\ &=\sum_{T=1}^nS([\frac{n}{T}])S([\frac{m}{T}])T\sum_{i|T}i\mu(i) \end{aligned}\]
    不難發現最後那一部分是一個積性函數,那麼\(\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\)就不說了。spa

  • \(\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\)。所以這兩個的狄利克雷卷積就是單位元。htm

  • \(\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\)blog

  • \(\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)\)
把二者卷積起來:
\[(g*f)(n)=\sum_{d|n}g(d)*f(\frac{n}{d})\]
而後考慮求解這個玩意的前綴和:
\[\begin{aligned} \sum_{i=1}^n (g*f)(i)&=\sum_{i=1}^n\sum_{d|i}g(d)f(\frac{i}{d})\\ &=\sum_{d=1}^ng(d)\sum_{j=1}^{n/d}f(i)\\ &=\sum_{d=1}^ng(d)S([\frac{n}{d}]) \end{aligned}\]
而後咱們驚奇的發現有這麼一個式子:
\[\begin{aligned} g(1)S(n)&=\sum_{i=1}^ng(i)S([\frac{n}{i}])-\sum_{i=2}^ng(i)S([\frac{n}{i}])\\ &=\sum_{i=1}^n (f*g)(i)-\sum_{i=2}^n g(i)S(\frac{n}{i}) \end{aligned}\]
那麼僞裝咱們能夠快速的計算\((f*g)\)的前綴和,那麼後半部分能夠數論分塊+遞歸求解。
這樣一來咱們就能夠還原出\(S(n)\)了。
因此。。。實際上杜教篩就是一個構造的過程。
那麼可以快速計算前綴和要有多好求呢?好比說咱們要求\(\mu\)的前綴和,那麼最好能夠\(O(1)\)求,而\(\mu*1=e\)\(e\)的前綴和就是\(1\),那就很好辦了。令\(f(x)=\mu(x),g(x)=1\),能夠獲得
\[\begin{aligned} S(n)&=1-\sum_{i=2}^nS([\frac{n}{i}]) \end{aligned}\]
這個東西?遞歸算算就行了。固然了,別少了記憶化。
推式子熟練了就很好了,而構造\(g\)的時候就記住前面講的幾個經常使用的狄利克雷卷積的式子,往那個上面靠。這裏隨便推一道題目能夠看看是怎麼構造的。get

  • 【洛谷3768】簡單的數學題
    前面的是莫比烏斯反演,推導過程會寫的比較簡單。
    \[\begin{aligned} Ans&=\sum_{i=1}^n\sum_{j=1}^nijgcd(i,j)\\ &=\sum_{d=1}^n d^3\sum_{i=1}^{n/d}\sum_{j=1}^{n/d}ij[gcd(i,j)=1]\\ &=\sum_{d=1}^n d^3\sum_{i=1}^{n/d}\mu(i)*i^2*S^2([\frac{n}{id}])\\ &=\sum_{T=1}^n S^2([\frac{n}{T}])\sum_{d|T} d^3(\frac{T}{d})^2\mu(\frac{T}{d})\\ &=\sum_{T=1}^n S^2([\frac{n}{T}])(T^2\sum_{d|T}d\mu(\frac{T}{d})\\ &=\sum_{T=1}^n S^2([\frac{n}{T}])(T^2\varphi(T))\\ \end{aligned}\]
    考慮怎麼求\(f(T)=T^2\varphi(T)\)的前綴和,這個東西顯然是一個積性函數。
    發現式子中帶\(\varphi\),因此杜教篩配\(g\)的時候往\(\displaystyle \sum_{d|T}\varphi(T)=T\)上面靠。
    \[\begin{aligned} (f*g)(n)&=\sum_{d|n}f(d)g(\frac{n}{d})\\ &=\sum_{d|n}d^2\varphi(d)g(\frac{n}{d})\\ \end{aligned}\]
    由於要往只有\(\varphi\)上靠,因此令\(g(x)=x^2\)
    \[\begin{aligned} (f*g)(n)&=\sum_{d|n}d^2\varphi(d)g(\frac{n}{d})\\ &=n^2\sum_{d|n}\varphi(d)\\ &=n^3 \end{aligned}\]
    那就很好辦了,\(\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)\)爲積性函數,因此轉移能夠寫成:
    \[g(n,j)=\begin{cases} g(n,j-1)&P_j^2>n\\ g(n,j-1)-f(P_j)(g([\frac{n}{P_j}],j-1)-g(P_j-1,j-1))&P_j^2\leq n \end{cases}\]
    前面也說了,\(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\)自己的貢獻沒有計算進來,因此要額外加進來。
    因此轉移就能夠寫成:
    \[S(n,j)=g(n,|P|)-\sum_{i=1}^{j-1}f(P_i)+\sum_{k\geq j}^{|P|}\sum_{e}(f(P_k^e)S([\frac{n}{P_k^e}],k+1)+f(P_{k}^{e+1}))\]

因此底下就來丟幾道題目吧。。。

  • 【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\),那麼顯然有轉移:
    \[g(n,j)=\begin{cases} g(n,j-1)&P_j^2>n\\ g(n,j-1)-P_j(g([\frac{n}{P_j}],j-1)-g(P_j-1,j-1))&P_j^2\le n \end{cases}\]
    \(h(n,j)\)表示\(k=0\)的狀況,即\(f(p)=1\)時的計算,那麼有轉移:
    \[h(n,j)=\begin{cases} h(n,j-1)&P_j^2>n\\ h(n,j-1)-(h([\frac{n}{P_j}],j-1)-h(P_j-1,j-1))&P_j^2\le n \end{cases}\]
    顯然有\(g(n,|p|)-h(n,|p|)\)爲全部質數的答案,假設其爲\(F(n)\)
    那麼設\(S(n,j)\)表示\(\displaystyle \sum_{i=2}^n f(i)\),其中\(i\)的最小質因子大於等於\(P_j\)
    獲得轉移:
    \[S(n,j)=F(n)-\sum_{i=1}^{j-1}f(P_j)+\sum_{k\geq j}\sum_e(f(P_k^e)S([\frac{n}{P_k^e}],k+1)+f(P_k^{e+1}))\]
    那麼簡單的遞歸處理便可。
    講講幾個實現的地方,首先要篩的質數只有\(\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記錄

相關文章
相關標籤/搜索