整除分塊學習筆記
前置知識
莫比烏斯反演
上面的標題應該改為後置知識
前言
最近在嗑莫比烏斯函式時嗑到了這個知識點,本質上是一個經常與莫比烏斯反演一起出現的小技巧,包括在很多莫比烏斯反演的題目中。
演算法過程
整除分塊通常被用來處理類似下方的式子:
\[\sum_{i=1}^n \lfloor \frac{n}{i} \rfloor \]暴力
首先我們可以暴力解決:
int ans = 0;
for(int i = 1; i <= n; i++) {
ans += n / i;
}
\[N \leq 10^9
\]然後就歇菜了
規律
我們可以通過打表的方式來尋找\(\sum_{i=1}^n \lfloor \frac{n}{i} \rfloor\)
當\(n=5,sum=5+2+1+1+1\)
當\(n=9,sum=9+4+3+2+1+1+1+1+1\)
當\(n=12,sum=12+6+4+3+2+2+1+1+1\)
可以看到有很多數是重複的,當\(n\)更大時,重複的數會更多。可以證明,這些數的數量是\(O(\sqrt{n})\)的。換句話說,我們可以將每一段連續且相同的數分開計算,實現\(O(\sqrt{n})\)的時間複雜度。
實現
可以證明,對於一段相同且連續的數,若其左端點為\(l\),則右端點為\(\lfloor \frac{n}{\lfloor \frac{n}{l} \rfloor} \rfloor\)
即這一段\(r-l+1\)
for(int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
ans += (n / l) * (r - l + 1);
}
應用
「CQOI2007」餘數求和
這道題的關鍵是求\(\sum_{i=1}^n i * \lfloor \frac{n}{i} \rfloor\)
在此題中,\(l\)到\(r\)的總和為\(\sum_{i=l}^{r} i * \lfloor \frac{n}{l} \rfloor = \lfloor \frac{n}{l} \rfloor \sum_{i=l}^{r} i = \lfloor \frac{n}{l} \rfloor * \frac{(l + r)(r - l + 1)}{2}\)
for(int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
ans += (n / l) * (l + r) * (r - l + 1) / 2;
}
莫比烏斯反演
在莫比烏斯反演中,我們經常需要求\(\sum_{i=1}^n \mu(i) * \lfloor \frac{n}{i} \rfloor\)
在同一段內的和為\(\sum_{i=l}^{r} \mu(i) * \lfloor \frac{n}{l} \rfloor = \lfloor \frac{n}{l} \rfloor \sum_{i=l}^{r} \mu(i) = \lfloor \frac{n}{l} \rfloor (\sum_{i=1}^{r} \mu(i) - \sum_{i=1}^{l-1} \mu(i))\)
使用線性篩可以在\(O(n)\)的時間內預處理所有的\(\sum_{i=1}^{k} \mu(i)\),整除分塊複雜度為\(O(\sqrt{n})\),總複雜度\(O(n)\)
for(int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + mu[i];
}
for(int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);
ans += (n / l) * (sum[r] - sum[l - 1]);
}
本文作者: Helium Air
出處:https://www.cnblogs.com/Helium-Air/
版權宣告: 本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。轉載請註明出處!