4数论分块
数论分块
数论分块可以快速计算一些含有除法向下取整的和式(即形如
$\sum_^nf(i)g(\left\lfloor\dfrac ni\right\rfloor) $的和式)。当可以在 $O(1) $内计算 \(f(r)-f(l)\) 或已经预处理出 f 的前缀和时,数论分块就可以在 \(O(\sqrt n)\) 的时间内计算上述和式的值。
它主要利用了富比尼定理(Fubini's theorem),将
$\left\lfloor\dfrac ni\right\rfloor $相同的数打包同时计算。
结论:
对于常数 n,使得式子$\left\lfloor\dfrac ni\right\rfloor=\left\lfloor\dfrac nj\right\rfloor$
成立且满足$ i\leq j\leq n$ 的 j 值最大为 \(\left\lfloor\dfrac n{\lfloor\frac ni\rfloor}\right\rfloor\),即值 $\left\lfloor\dfrac ni\right\rfloor $所在块的右端点为 \(\left\lfloor\dfrac n{\lfloor\frac ni\rfloor}\right\rfloor\)。
过程:
数论分块的过程大概如下:考虑和式
\(\sum_{i=1}^nf(i)\left\lfloor\dfrac ni\right\rfloor\)
那么由于我们可以知道
$\left\lfloor\dfrac ni\right\rfloor $的值成一个块状分布(就是同样的值都聚集在连续的块中),那么就可以用数论分块加速计算,降低时间复杂度。
利用上述结论,我们先求出 f(i) 的 前缀和(记作
\(s(i)=\sum_{j=1}^i f(j))\),然后每次以
$[l,r]=[l,\left\lfloor\dfrac n{\lfloor\frac ni\rfloor}\right\rfloor] $为一块,分块求出贡献累加到结果中即可。
代码如下:
int result=0;
for(int l=1,r;l <= n; l = r + 1)
{
r = n/(n/l);
k = n / l;
result += (s[r] - s[l-r]) * k;
}
最终得到的 result 即为所求的和式。
向上取整的数论分块
向上取整与前文所述的向下取整十分类似,但略有区别:
对于常数 n,使得式子
\(\left\lceil\dfrac ni\right\rceil=\left\lceil\dfrac nj\right\rceil\)
成立且满足 \(i\leq j\leq n\) 的 j 值最大为
\(\left\lfloor\dfrac{n-1}{\lfloor\frac{n-1}i\rfloor}\right\rfloor\),即值
$\left\lceil\dfrac ni\right\rceil $所在块的右端点为
\(\left\lfloor\dfrac{n-1}{\lfloor\frac{n-1}i\rfloor}\right\rfloor\)
当 i=n 时,上式会出现分母为 0 的错误,需要特殊处理。

浙公网安备 33010602011771号