首先我們給道題目:求\(\sum\limits_{i=1}^n\mu(i)\)
\(n\leqslant 10^5\),我會\(O(n\sqrt{n})\)!
\(n\leqslant 10^7\),我會\(O(n)\)線篩!
\(n\leqslant 10^9\),我……
於是杜教篩就此被發明,它可以在\(O(n^{\frac{2}{3}})\)的時間內求出一些積性函數函數的前綴和,如何做?
假定我們現在要求\(S(n)=\sum\limits_{i=1}^nf(i)\),於是我們找來一個積性函數\(g(i)\)(不知道是什么東西),和\(f(i)\)卷積一下,有
然后我們求一下卷積形式的前綴和
然后我們調整一下枚舉順序,得到
好,我們現在得到\(\sum\limits_{i=1}^n(f*g)(i)=\sum\limits_{d=1}^ng(d)S(\lfloor\dfrac{n}{d}\rfloor)\),然后我們把這個先放着,稍微思考一下,顯然有如下式子
然后你發現中間一個和我們之前推出來的形式是一樣的,於是有
如果中間卷積部分的前綴和非常好算,那么我們就可以對后面那部分進行數論分塊,然后遞歸處理,記得記憶化!
我們回到栗子,題目要求的\(f\)就是\(\mu\)對吧,代回去有
現在我們需要找一個優秀的\(g\),使得他們狄利克雷卷積的前綴和非常好算
我們知道
所以\((1*\mu)=e\),你說\(e\)的前綴和是啥,當然是1啦,於是我們取\(g(x)=1\),有
然后我們線篩出一部分\(\mu\)的前綴和,再來一波記憶化搜索,做完了
再舉個栗子,把\(\mu\)換成\(\varphi\)該怎么做?
因為有
所以還是取\(g(x)=1\),那么得到
\(S(n)=\sum\limits_{i=1}^ni-\sum\limits_{i=2}^nS(\lfloor\dfrac{n}{i}\rfloor)\)
等差數列前綴和\(O(1)\)求出就好了
對於不同的\(f\),只要找到合適的\(g\),就就可以讓你的程序變得非常好寫
不會找沒關系,打個表解決一切
不過記得不要有事沒事想着杜教篩,線篩啥的,埃氏篩法也是很有用的,\(O(n\ln n)\)枚舉倍數也挺好的
騙分過樣例,暴力出奇跡
扯了這么多,講下時間復雜度證明吧
其實可以發現除了\(S(n)=\sum\limits_{i=2}^nS(\lfloor\dfrac{n}{i}\rfloor)\)貢獻了復雜度外,其他基本上可以\(O(1)\)算出答案(惡心的\(g(n)\)不考慮)
那么我們只要算出\(\sqrt n\)個\(S(\lfloor\dfrac{n}{i}\rfloor)\)的值即可算出\(S(n)\),於是我們設\(T(n)\)為計算出\(S(n)\)的復雜度,那么有
其中\(O(\sqrt n)\)是累加合並的時間
然后我們展開一層,因為更深層的復雜度是高階小量,所以有
但由於\(S(n)\)本身是可以通過線篩求出一部分的,假定我們預處理了前\(k\)個的值,且\(k\geqslant \sqrt n\),則復雜度變為
則當\(k\)取\(n^{\frac{2}{3}}\)時可以取到較好的復雜度\(T(n)=O(n^{\frac{2}{3}})\)