【数论分块入门】
数论分块
通常用来解决 \(\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor\) 这种问题。
我们代入 n = 10。
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
\(\lfloor\frac{n}{i}\rfloor\) | 10 | 5 | 3 | 2 | 2 | 1 | 1 | 1 | 1 | 1 |
可以看到后面有连续的 \(i\), \(\lfloor\frac{n}{i}\rfloor\) 相同。呈现块状分布
每个块的起点 \(l\) 和终点 \(r\) 满足规律:\(r=\lfloor\frac{n}{\lfloor\frac{n}{l}\rfloor}\rfloor\)
而 \(\lfloor\frac{n}{i}\rfloor\) 的有效取值只有 \(O(\sqrt n)\) 个,求解 \(\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor\) 就可以快速的实现了。
int ans=0;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
例题
P2261 [CQOI2007]余数求和
给出正整数 n 和 k,请计算
\[G(n, k) = \sum_{i = 1}^n k \bmod i
\]
其中 \(k\bmod i\) 表示 k 除以 i 的余数。
化简给出的式子 \(k \bmod i=k-\lfloor\frac{k}{i}\rfloor\times i\)
\[\begin{aligned}
G(n, k) &= \sum_{i = 1}^n k \bmod i\\
&=\sum_{i=1}^n(k-\lfloor\frac{k}{i}\rfloor\times i)\\
&=n\times k-\sum_{i=1}^n(\lfloor\frac{k}{i}\rfloor\times i)
\end{aligned}
\]
对于 \(\sum_{i=1}^n(\lfloor\frac{k}{i}\rfloor\times i)\),每个块我们求出 \([l,r]\) 的和 乘 当前块的 \(\lfloor\frac{k}{i}\rfloor\)
累加起来即可
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 2e5 + 10;
int main()
{
ll n, k;
scanf("%lld%lld", &n, &k);
ll ans = 0;
for (ll l = 1, r; l <= min(n, k); l = r + 1) {
r = min(n, k / (k / l));
ans += (l + r) * (r - l + 1) / 2 * (k / l);
}
printf("%lld\n", n * k - ans);
return 0;
}
P1403 [AHOI2005]约数研究
\(f(i)\) 表示 \(i\) 的约数的个数,给出 \(n\) ,请求出 \(\sum_{i=1}^{n}f(i)\)
枚举约数 \(i\),显然,区间 \([1,n]\) 中,有 \(\lfloor\frac{n}{i}\rfloor\) 个数字是 \(i\) 的倍数。
答案即为 \(\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor\)