当 1 ≤ i ≤ ⌊ n ⌋ 1 \le i \le \lfloor \sqrt n \rfloor 1≤i≤⌊n⌋时, ⌊ n i ⌋ \lfloor \frac{n}{i} \rfloor ⌊in⌋的不同数值个数显然是不超过 ⌊ n ⌋ \lfloor \sqrt n \rfloor ⌊n⌋。
当 ⌊ n ⌋ < i ≤ n \lfloor \sqrt n \rfloor < i \le n ⌊n⌋<i≤n时,因为 1 ≤ ⌊ n i ⌋ ≤ n 1 \le \lfloor \frac{n}{i} \rfloor \le \sqrt n 1≤⌊in⌋≤n,所以不同数值个数还是不超过 ⌊ n ⌋ \lfloor \sqrt n \rfloor ⌊n⌋。
综合上述两种情况, ⌊ n i ⌋ \lfloor \frac{n}{i} \rfloor ⌊in⌋的不同数值个数严格不大于 2 n 2 \sqrt n 2n
“数论分块”这个名词,其实比较模糊,没有一个广泛认同的严格定义。这里讲一下我个人的理解:
令 f ( i ) = ⌊ n i ⌋ f(i)=\lfloor \frac{n}{i} \rfloor f(i)=⌊in⌋
f ( i ) f(i) f(i)的值,随着 i i i的增加而单调不增,如果我把 f ( 1 ) , f ( 2 ) , … , f ( n ) f(1),f(2),\dots,f(n) f(1),f(2),…,f(n)从左到右排开,会发现其值呈现出“块状”,每一个“块”就是连续的一段,每个“块”中 f ( i ) f(i) f(i)的值都是相同的
举个例子, n = 5 n=5 n=5
f ( 1 ) = 5 , f ( 2 ) = 2 , f ( 3 ) = f ( 4 ) = f ( 5 ) = 1 f(1)=5,f(2)=2,f(3)=f(4)=f(5)=1 f(1)=5,f(2)=2,f(3)=f(4)=f(5)=1,一字排开,得到 5 , 2 , 1 , 1 , 1 5,2,1,1,1 5,2,1,1,1,相同的分到一个“块”中,直观一点,写成: [ 5 ] , [ 2 ] , [ 1 , 1 , 1 ] [5],[2],[1,1,1] [5],[2],[1,1,1]
数论分块从直观上来讲就是这个现象
数论分块中,块的右端是个很重要的位置。比如例子 n = 5 n=5 n=5中,三个块右端的编号分别是 1 , 2 , 5 1,2,5 1,2,5
如果一个块的 f f f值是 t t t,对于其中的数 x x x,应当满足 ⌊ n x ⌋ = t \lfloor \frac{n}{x} \rfloor=t ⌊xn⌋=t,即 n = t x + r ( 0 ≤ r < x ) n=tx+r(0\le r
比如上面那个例子,值域是 { 1 , 2 , 5 } \{1,2,5\} {1,2,5},块右端下标集合也是 { 1 , 2 , 5 } \{1,2,5\} {1,2,5}
解释:
假设一个块的 f f f值是 t t t,右端是 x x x,那么 ⌊ n t ⌋ = x , ⌊ n x ⌋ = t \lfloor \frac{n}{t} \rfloor=x, \lfloor \frac{n}{x} \rfloor=t ⌊tn⌋=x,⌊xn⌋=t
也就是说 x x x和 t t t一一对应,不同块的 f f f值不会相同,一个 f f f值也不会对应多个块,这就说明了块“右端“集合和 f f f的值域值域这两个集合大小相同
那么元素是否也是相同的呢?是的,因为假设一个元素 p p p属于"块右端"集合,那么根据“块右端”的计算方法,得知某个肯定存在某个 t t t使得 ⌊ n t ⌋ = p \lfloor \frac{n}{t} \rfloor=p ⌊tn⌋=p,也就是 f ( t ) = p f(t)=p f(t)=p,也就是说 p p p也属于 f f f的值域值域集合。
因为两个集合大小相同,而且“块右端”集合中的每个元素也在值域集合中出现,所以这两个集合相等
上面提到过一个式子:
n = t x + r ( 0 ≤ r < x ) n=tx+r(0\le r
当 x < ⌊ n ⌋ x< \lfloor \sqrt n \rfloor x<⌊n⌋的时候,如果我在上式中用 x + 1 x+1 x+1替换 x x x,假设 t t t可以保持不变,那么就有
n = t ( x + 1 ) + r ′ ( 0 ≤ r ′ < x + 1 ) n = t(x+1) +r' (0 \le r' < x+1) n=t(x+1)+r′(0≤r′<x+1)
也就是 n = t x + ( t + r ′ ) n = tx + (t +r') n=tx+(t+r′),那么 t + r ′ = r t+r'=r t+r′=r
但是由于 x < ⌊ n ⌋ x< \lfloor \sqrt n \rfloor x<⌊n⌋,所以 t = ⌊ n x ⌋ > ⌊ n ⌋ > x t =\lfloor \frac{n}{x} \rfloor > \lfloor \sqrt n \rfloor > x t=⌊xn⌋>⌊n⌋>x
那么显然 t + r ′ > x t+r' > x t+r′>x
也就是与我一开始的假设相矛盾了
从而也就证明了结论三
在杜教筛中,我们要存储 S ( ⌊ n i ⌋ ) S(\lfloor \frac{n}{i} \rfloor) S(⌊in⌋)的所有可能值
如果单纯考虑空间最优,我们应该只需要开 O ( n ) O(\sqrt n) O(n)规模的空间
但是算法还受到时间限制,最后通过均值不等式我们发现最好是预处理到 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)可以得到一个最优的时间复杂度。当然实际中还是要调参,因为各个部分的时间占比并非相同。
回归正题,在 m i n 25 min25 min25筛和杜教筛中我们都要解决一个问题:存储一些数据,这些数据的下标很大,但是这些下标都在 ⌊ n i ⌋ \lfloor \frac{n}{i} \rfloor ⌊in⌋的值域中。根据本文所介绍的理论,当 i ≤ ⌊ n ⌋ i\le \lfloor \sqrt n \rfloor i≤⌊n⌋的时候直接块右端(根据结论三,块右端就是 1 , 2 , … , ⌊ n ⌋ 1,2,\dots,\lfloor \sqrt n \rfloor 1,2,…,⌊n⌋)为下标,而当 i > ⌊ n ⌋ i > \lfloor \sqrt n \rfloor i>⌊n⌋的时候以值为下标。
大的部分想调用的时候,直接计算一下块右端下标就可以访问了。
这样调用是 O ( 1 ) O(1) O(1)的,显然比用map
或者unorderd_map
快得多