双曲线下整点计数——SBT的一点应用

· · 个人记录

Part 0. 前言

本篇为笔者学习 DIVCNT1 时留下的一点学习小记,公式之类的笔误可以直接在评论区提出,笔者会尽快修复。

Part 1. 问题的引入

给定双曲线:

T_2:xy=n

T_1 下方的整点个数(含经过的点, 1\leq n\leq 2^{63} )。

Part 2. 问题的初步探讨

原式即等价于求:

S_1(n,x_1,x_2)=\sum_{x=x_1}^{x_2}[\dfrac{n}{x}],x_1=1,x_2=n

记原式答案为 T_2(n) ,则有:

T_2(n)=S_1(n,1,n)=2S_1(n,1,[\sqrt{n}])-[\sqrt{n}]^2

至此,我们已经可以在 \Theta(\sqrt{n}) 的 naive 复杂度下解出答案,但显然我们需要更快的做法。

Part 3. Stern-Brocot Tree 和 Farey 序列的引入

Stern-Brocot Tree (以下简称 SBT ): SBT 是一棵无穷大的完全二叉树,每个节点都代表一个最简分数,且与有理数对应。它满足搜索树的性质,即左子树的所有数都小于根代表的数,右子树的所有数都大于根代表的数。(其它有趣的性质可参见 BiliBili的小视频 )

抓一张图过来以便于理解:

(当然图中的这棵树只是 SBT 的一部分)

Farey 序列: 将所有分母小于等于 n 的最简真分数从小到大排列,形成的序列即为 Farey 序列。我们称在 Farey 序列中连续出现的分数为 Farey Neighbour 。若 \dfrac{a}{b}\dfrac{c}{d} 为 Farey Neighbour ,且 \dfrac{a}{b}>\dfrac{c}{d},则有: ad-bc=1 。(证明可食用参考文献)

(图片有点小。。请见谅 >_< )

如上的科技将会对我们解题有帮助。

Part 4. 问题的深入探讨

回到原题,我们求的即为满足: xy\leq n , y\leq[\sqrt{n}] 且在坐标轴正半轴右上方的整点个数。

贺一著名图片:

我们考虑利用 SBT 切割曲线,如下图所示:

我们很容易能统计出红线下方的整点数。

那么怎么搞右边和上面的部分呢?

首先,我们定义一个函数 S(x_0,y_0,a,b,c,d) 。在下图中, P 点的坐标即为 (x_0,y_0) ,过 P 的两条直线 QP,RP 的斜率分别是 -\dfrac{a}{b}-\dfrac{c}{d}R,Q 在双曲线上。 曲边三角形 PQR 内的整点个数即为 S(x_0,y_0,a,b,c,d) 。当 \dfrac{a}{b}\dfrac{c}{d} 不是 Farey Neighbour 时,定义 S(x_0,y_0,a,b,c,d)=0

所以我们要求的是 S(0,0,1,0,0,1)

我们尝试将原来的 xy 坐标系转化为这里的 PR,PQ 轴坐标系。不妨记 PRR 轴,PQQ 轴。由定义可知:

x=x_0+ud-vb,\space y=y_0-uc+va

所以可得:

ax+by=ax_0+by_0+(ad-bc)u

由 Farey 序列的性质,我们可以知道原坐标系与 QR 坐标系的点一一对应。

所以原来的双曲线 T_2:xy=n 可以被转化为 QR 坐标系中的曲线。那么令:

w_1=ax_0+by_0,\space w_2=cx_0+dy_0

有:

x_0=dw_1-bw_2,\space y_0=aw_2-cw_1

所以原双曲线 T_2:xy=n 可转化为 QR 坐标系中的曲线:

H(u,v):(u+w_1)(v+w_2)-cd(u+w_1)^2-ab(v+w_2)^2=n

因为 w_1,w_2,ab,cd\geq 0 ,所以对于任意 u>0 ,有唯一对应的 v 。对于 v>0 ,也有唯一对应的 u

Q 点在 Q 坐标轴上的坐标轴为 h_1R 点在 R 坐标轴上的坐标轴为 h_2 。所以我们实际在统计下图中绿线和黑线的左下方部分的整点数量。

如果转化后的问题可解决,那么向下递归,即可做出原问题(在较靠近边界的部分可以暴力计算)。

考虑如何计算转化后的问题,找到 QR 坐标系下斜率为 -1 的点 G ,也就是原坐标系中斜率为 -\dfrac{a+c}{b+d} 的曲线,如下图所示:

于是可以找到另两个整点 S,T 满足:

R_S\leq R_G<R_S+1=R_T,\space Q_S=[Q(R_S)],\space Q_T=[Q(R_T)],

S,T 作切线 G 的平行线:

折线 ASTB 下的整点显然能搞,尝试搞剩下的部分。因为蓝线在原坐标系下的斜率为 -\dfrac{a+c}{b+d} 。由 SBT 的性质,可以得出 \dfrac{a+c}{b+d}\dfrac{a}{c},\dfrac{b}{d} 为 Farey Neighbour ,所以我们可以向下迭代计算。

上方的整点数即为 S(X_B,Y_B,a,b,a+c,b+d) ,右边为 S(X_C,Y_C,a,b,a+c,b+d)

论文中将本方法的复杂度证明在了 \Theta(n^\frac{1}{3}\log^3n) ,可能能做到 \Theta(n^\frac{1}{3}\log n)

Part 5. 优化

事实上,如上的反复切割函数并非必要。我们可以直接用 SBT 来拟合原来的曲线,像下面这样:

取一只单调栈,因为曲线逐渐趋缓,斜率始终保持在 [-1,0] ,因此栈中斜率初始化为 (1,0),(1,1) ,按照斜率单调下降存储。由推得的式子,我们从 ([\dfrac{n}{[\sqrt{n}]}],[\sqrt{n}]+1) 出发。

假设我们拟合到了点 A(x,y) ,那么下一次拟合一定在该点的右侧,且不在蓝色区域内。设下一个点为 B(p,q) ,那么由 Pick 定理,贡献就是:

x(y-q)+\frac12 (y-q+1)(p-x+1)

那么怎么确定这个 B(p,q) 呢?

我们可以取栈顶向量,弹出,然后不断加上它,直到差一步走进蓝色区域。记该向量为 right ,记上一次弹的是 left 。用 SBT 合成出和向量 mid

如果 mid 走一步没有进蓝色区域,那么把 right 替换为 mid ,重复步骤。如果走一步进了,且 right 小于等于 rightmid 的和向量,则可以直接停止。反之则将 left 替换为 mid

y\leq n^{\frac{1}{3}} 的时候可直接暴力。

可以证明复杂度为 \Theta(n^{\frac{1}{3}}) ,具体证明同见论文。

Part 6. 问题的一点点推广

我们来求一下三维空间中的“双曲线”下整点个数,即:

T_3:xyz=n 还是将它化为合式的形式: $$\sum_{z=1}^n\sum_{x=1}^n[\dfrac{n}{xz}]$$ 也就是: $$T_3(n)=\sum_{z=1}^nT_2(\dfrac{n}{z})$$ ~~偷懒贴一下论文:~~ ![](https://cdn.luogu.com.cn/upload/image_hosting/adzrf52w.png) 于是我们就获得了 $$\sum_{z=1}^{n^\frac{1}{3}}\Theta([\frac{n}{z}]^\frac13)=\Theta(\int_1^{n^\frac13}[\frac{n^\frac13}{z^\frac13}]\space dz)=\Theta(n^\frac{5}{9})$$ 的时间复杂度。 **Part 7. 参考文献** ```cpp https://max.book118.com/html/2019/0311/5241020123002020.shtm http://export.arxiv.org/pdf/1206.3369 ``` 感谢上述文章的作者,使得笔者对 SBT 有了初步了解。