【数论分块入门】

数论分块

通常用来解决 \(\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\)

posted @ 2020-11-27 09:47  Valk3  阅读(100)  评论(0编辑  收藏  举报