一. 核心定理
整除分块,又称数论分块,其核心是一个定理。
定理:设 diff 函数为求不同数值的个数,如 diff{1,1,3,4,6,6,6}=4,则 i=1diffi≤n⌊in⌋ 最大不超过 2n。
证明:
-
考虑 i∈[1,n],最多 n 个。所以 i=1diffi≤n⌊in⌋ 最大不超过 n。
-
考虑 i∈(n,n],⌊in⌋ 的值单调不增。⌊⌈n⌉n⌋ 的值最大为 n,⌊nn⌋ 为 1。所以 i=⌈n⌉diffi≤n⌊in⌋ 最大不超过 n。
证毕。
二. 确定分界点
上一个标题中,我们认识到整除分块复杂度的正确性。这一个标题将会讲解如何确定块与块之间的分界点。
设 gn(x) 为大于等于 x 且被 n 整除的值与 x 被 n 整除的值相同的最大整数。可用公式表示为:
⌊xn⌋=⌊gn(x)n⌋,⌊xn⌋>⌊gn(x)+1n⌋
定理:gn(x)=⌊⌊xn⌋n⌋
证明:只要证明了上面“可用公式表示为”的两个式子成立,即可完成证明。
-
证明第一个式子
首先引入三个显然的东西:
-
⌊n⌋≤n。
-
如果 n≤m,那么 ⌊n⌋≤⌊m⌋。
-
如果 n∈Z,那么 ⌊n⌋=n。
开始证明:
-
证明 x≤⌊⌊xn⌋n⌋
xn≥⌊xn⌋又∵xn,⌊xn⌋=0⟹xnn≤⌊xn⌋n⟹⌊xnn⌋≤⌊⌊xn⌋n⌋⟹⌊x⌋≤⌊⌊xn⌋n⌋⟹x≤⌊⌊xn⌋n⌋
这条结论在接下来的证明中一直会用到。
这一步相当于是证明了 x≤gn(x)。
-
证明 ⌊xn⌋≥⌊gn(x)n⌋
x≤gn(x)又∵x,gn(x)=0⟹xn≥gn(x)n⟹⌊xn⌋≥⌊gn(x)n⌋
-
证明 ⌊xn⌋≤⌊gn(x)n⌋
即证⌊xn⌋≤⎣⎢⌊⌊xn⌋n⌋n⎦⎥设x′=⌊xn⌋即证x′≤⎣⎢⌊⌊x′⌋n⌋n⎦⎥,该式已被证明
综上所述,⌊xn⌋=⌊gn(x)n⌋
-
证明第二个式子
我们先设一下带余除法,带余除法是数论证明的常用手段,它能有效地消掉下去整号。
设 n=kx+b (0≤b<x),则 ⌊xn⌋=k。
设 n=pk+q (0≤q<k),则 ⌊kn⌋=p。
若证⌊xn⌋>⌊gn(x)+1n⌋即证⌊xn⌋>⎣⎢⌊⌊xn⌋n⌋+1n⎦⎥即证k>⌊⌊kn⌋+1n⌋即证k>⌊p+1n⌋
这里需要先证一个小结论:若 a,b,c∈Z,a>⌊cb⌋,则 ac>b。
∵a∈Z,a>⌊cb⌋∴a>cb∴ac>b
接着主线的证明:
即证k(p+1)>n即证n<pk+k又∵n=pk+q,q<k.该式成立
综上所述,gn(x)=⌊⌊xn⌋n⌋。
三. 应用
主要用于解决求类似 i=1∑i≤n⌊in⌋ 的式子,如果直接暴力求时间复杂度是 O(n) 的,使用整除分块可以降到 O(n)。
求 i=1∑i≤n⌊in⌋ 的代码示例:
1 2 3 4
| for (int il = 1, ir = min(n, n / (n / il)); ; il = ir + 1, ir = min(n, n / (n / il))) { if (ir == n) break; }
|
注意 l > n
后运行这个语句会出现除零错,所以要在每个循环体的末尾判 break
而非 for
的第二个位置。
例题:
[CQOI2007]余数求和
[POI2007]ZAP-Queries