這個是學習莫比烏斯反演須要的預備知識,幾乎全部這類的題都須要用到這個。html
考慮下面這個式子:
\[ \sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor \]
這個固然能夠\(O(n)\)算,可是不少時候這樣還不夠快,因而下面有一個\(O(\sqrt{n})\)的算法。算法
經過打表能夠發現,當\(i\)爲連續一段時,後面那玩意都是同樣的。函數
而後對於\(i\),最後一個和它相同的位置是\(n/(n/i)\),注意這裏都是整除,而後共有\(O(\sqrt{n})\)個塊,因此咱們就能夠每次跳一個塊,快速算出結果,代碼以下:學習
int n;read(n); int ans=0,T=1; while(T<=n) { int pre=T;T=n/(n/T); ans=ans+(T-pre+1)*(n/T);T++; } write(ans);
關於莫比烏斯函數,其實並非一個很玄學的東西,它本質上就是一個容斥係數。spa
對於莫比烏斯函數,它寫做\(\mu(d)\),定義以下:code
而後對於這個函數有一個最爲重要的性質:
\[ \sum_{d|n}\mu(d)=[n=1] \]
證實其實很簡單,將\(n\)進行惟一分解,獲得\(n=\prod_{i=1}^ka_i^{p_i}\)只須要考慮容斥,對於\(n\)的每個因數只能選或不選,則:
\[ \sum_{d|n}\mu(d)=\sum_{i=0}^{k}(-1)^i\binom{k}{i}=[k=0] \]
而後\([k=0]\)其實等價於\([n=1]\),得證。htm
線篩也很簡單,根據定義就能夠了,代碼:blog
void sieve() { mu[1]=1; for(int i=2;i<maxn;i++) { if(!vis[i]) pri[++tot]=i,mu[i]=-1; for(int t,j=1;j<=tot&&i*pri[j]<maxn;j++) { vis[t=i*pri[j]]=1; if(!(i%pri[j])) {mu[t]=0;break;} mu[t]=-mu[i]; } } }
前置知識講完了,其實真的很水。get
定義\(f(n)\)和\(g(n)\),已知:
\[ f(n)=\sum_{d|n}g(d) \]
而後已知\(f\),求\(g\)。it
其實這個和推容斥差不太多,因爲我想把前面的莫比烏斯函數的性質用上,因此先說一句廢話:
\[ g(n)=\sum_{d|n}[\frac{n}{d}=1]g(d) \]
而後發現這個東西和上面長的很像,帶進去:
\[ \begin{align} g(n)&=\sum_{d|n}\sum_{i|\frac{n}{d}}\mu(i)g(d)\\ &=\sum_{d|n}g(d)\sum_{i|\frac{n}{d}}\mu(i) \end{align} \]
而後先枚舉\(i\):
\[ \begin{align} g(n)&=\sum_{i|n}\mu(i)\sum_{d|\frac{n}{i}}g(d) \end{align} \]
而後後面那個式子其實就是\(f\),因此:
\[ g(n)=\sum_{d|n}\mu(d)f(\frac{n}{d}) \]
而後就作完了。
這個東西就是莫比烏斯反演:
已知
\[ f(n)=\sum_{d|n}g(d) \]
那麼能夠獲得:
\[ g(n)=\sum_{d|n}\mu(d)f(\frac{n}{d}) \]
其實作題的話,直接把\(\sum_{d|n}\mu(d)=[n=1]\)帶到題目給的式子裏更好推一些。
最主要的仍是多作題,作多了就會發現其實都是一個套路,還有就是式子要本身拿紙筆來推,這點很重要。
(題目難度基本按順序排列,推薦按順序寫)