Trick-整除分块(数论分块)
整除分块:
对于类似于 \(solve_{d=1}^{n}(\frac{n}{d})\) 的式子, \(\frac{n}{d}\) 的值的个数不超过 \(\sqrt n\) 个(下面有证明),故可以对于每一个结果去计算其贡献。
代码如下:
for(int l = 1, r; l <= n; l = r + 1) {
r = n / (n / l);// d 在区间 [l, r] 的 n/d 大小相同
ans += n / l * solve(l, r);
}
复杂度证明:
记\(\dfrac{n}{d}\) 为 \(x\)。\(x\) 的取值范围在 \([1,n]\)。容易发现,\([1,\sqrt n]\) 的x更密集,\((\sqrt n, n]\) 的 \(x\) 更稀疏。
因为 \(d\) 从 \(1\) 到 \(n\) ,只有 \(d\) 在 \([1, \sqrt n]\) 时,\(\dfrac{n}{d}\) 在 \((\sqrt n, n]\),所以\(\dfrac{n}{d}\) 在 \((\sqrt n, n]\) 的个数不超过 \(\sqrt n\).
\(\dfrac{n}{d}\) 从 \(1\) 到 \(\sqrt n\) 一共 \(\sqrt n\) 个数,所以总个数为 \(O(\sqrt n)\) 的,本质上就是一个根号分治的思想。
一般式子中出现下取整,并且是分母一直在变,直接无脑整除分块。(P.S. 如果是分子在变,可以考虑类欧或万欧,分子分母都在变,可以考虑是否可让一个不变)
\(solve_{d=1}^{n}(\frac{a}{d}\frac bd)\) 这种式子也可以整除分块。
for(int l = 1, r; l <= n; l = r + 1) {
r = min({n, a / (a / l), b / (b / l)});
ans = ans + 1ll * (b / l) * (a / l) * (sm[r] - sm[l - 1]);
}
复杂度 \(O(\sqrt n)\)。
这相当于在数轴上对 \(a\) 撒 \(O(\sqrt n)\) 个点,对 \(b\) 撒 \(O(\sqrt n)\) 个点,加起来还是 \(O(\sqrt n)\) 个点。

浙公网安备 33010602011771号