Stern-Brocot Tree

Stern-Brocot Tree

定义两个既约分数 \(\frac{a}{b},\frac{c}{d}\) 的中位分数为 \(\frac{a+c}{b+d}\)

我们从 \(\frac{0}{1},\frac{1}{1},\frac{1}{0}\) 开始,每次向每相邻两个数中间插入它们的中位分数。

\[\begin{aligned} \frac{0}{1},&\dfrac{1}{1},\frac{1}{0}\\ \\ \frac{0}{1},\frac{1}{2},&\frac{1}{1},\frac{2}{1},\frac{1}{0}\\ \\ \frac{0}{1},\frac{1}{3},\frac{1}{2},\frac{2}{3},&\frac{1}{1},\frac{3}{2},\frac{2}{1},\frac{3}{1},\frac{1}{0} \end{aligned} \]

你把新插入的数排成新的一排,你发现这是一棵完全二叉树的形式。这个树就叫 Stern-Brocot Tree。

我们说一些性质。

每次排出的序列单增。

归纳证明,只需要证明 \(\frac{a}{b}<\frac{a+c}{b+d}<\frac{c}{d}\) 即可,这是简单的。

排出的序列中,相邻两个数 \(\frac{a}{b},\frac{c}{d}\) 满足 \(bc-ad=1\)

仍然归纳即可。

每个分数都是既约的。

\(bc-ad=1\) 和裴蜀定理立得。

每个既约分数都出现过。

你考虑一个类似于二分向下查找的过程,你每二分一次,你的 \(bc-ad\) 就会减小,最后减到 1。《具体数学》上给了一个不一样,更加严谨的证明,给出分数 \(\frac{a}{b}\) 构造出来至多需要 \(a+b\) 次。

upd:我上面这个做法,可以估出更好的界,明显这个界是 \(\max(a,b)\),我大概看了一眼应该也是紧的。

接下来给出一些在这个树上跑的办法。

我们认为根是 \(\frac{1}{1}\),向 左/右 记作 L/R。

先给出从 LR 序列对应到分数的方法。

我们对于树上的节点,记录矩阵 \(\begin{bmatrix}a&c\\ b&d\end{bmatrix}\) 表示它的左右祖先。

这样一个 L 操作对应矩阵 \(\begin{bmatrix}1&1\\ 0&1\end{bmatrix}\),R 对应 \(\begin{bmatrix}1&0\\ 1&1\end{bmatrix}\)(右乘)。

这样把 LR 序列中相邻相同项合并快速幂即可。

再给出从分数到 LR 序列的方法。

首先我们可以使用类似二分的方法一步步找,每次修改左右边界。

但是,我们还有一种同样的方法,不同的表示形式。

假设你现在知道了第一步走的是 L,因为 L 矩阵的逆是 \(\begin{bmatrix}1&-1\\ 0&1\end{bmatrix}\),所以你可以把你要求的分数 \(\frac{x}{y}\) 也应用这个变换,你发现得到 \(\frac{x}{y-x}\)。所以我们得到这样一个算法:

如果 \(x<y\),那么 \(y\leftarrow y-x\),否则 \(x\leftarrow x-y\)

终止条件是 \(x=y=1\)

你发现这个过程其实就是辗转相减,那你也可以用辗转相除优化一下。

这样我们还顺便证明了另一个性质:一个数 \(\frac{x}{y}\) 到根的路径上,转弯的次数不会超过 \(\log\) 次。

当然,你也可以采用倍增的方法。

https://atcoder.jp/contests/abc333/tasks/abc333_g

posted @ 2024-01-24 17:04  PYD1  阅读(12)  评论(0)    收藏  举报