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