#lCAybttg040408. 1559:跳跳棋

1559:跳跳棋

题目描述

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。棋盘上有三颗棋子,分别在 a,b,ca, b, c 这三个位置(保证 a<b<ca < b < c)。我们要通过最少的跳动把他们的位置移动成 x,y,zx, y, z(注意:棋子是没有区别的,所以只要求最终三个位置是 {x,y,z}\{x,y,z\} 的某种排列即可)。

跳动的规则很简单:任意选一颗棋子,以另一颗棋子为中轴跳动。跳动后两颗棋子距离不变。一次只允许跳过一颗棋子。

具体来说,假设三颗棋子位置从左到右为 l,m,rl, m, rl<m<rl < m < r),那么一次操作可以选择:

  1. llmm 为中轴跳到对称位置:新位置 l=2mll' = 2m - l(必须保证 lml' \ne mlrl' \ne r,且 ll' 在数轴上不与已有棋子重合,但题目允许 ll'mmrr 之间吗?规则是“对一颗中轴棋子跳动”,并且“一次只允许跳过一颗棋子”,这意味着只能向远离中轴的方向跳,不能跳到中间)。

    严格解释:对于 l,m,rl,m,r,如果 ml<rmm-l < r-m,则 ll 可以跳过 mm 跳到 mm 右边,新位置为 m+(ml)=2mlm + (m-l) = 2m-l,且必须保证 2ml<r2m-l < r 吗?不对,那样就会跳到 mmrr 之间,但规则说“一次只允许跳过一颗棋子”,如果 ll 跳到 mmrr 之间,那么它跳过了 mm,但没有跳过 rr,是允许的。但这样会导致棋子位置不再是单调顺序,需要重新排序。实际上操作后三个位置需要重新排序。

    更清晰的定义:设三颗棋子位置为 a,b,ca,b,c(不一定有序),每次操作可以选择一个棋子 pp 和另一个棋子 qq 作为中轴,将 pp 跳到关于 qq 的对称位置 p=2qpp'=2q-p,且要求 pppp' 之间仅有一颗棋子 qq(即 ppqq 的距离等于 qqpp' 的距离,且 pp' 处原来没有棋子)。由于棋子不可区分,最终状态只需集合相同。

    为了简化,我们假设 a<b<ca<b<c,则只有两种可能的操作:

    • aa 关于 bb 对称跳到 a=2baa'=2b-a(必须 aba' \ne baca' \ne c,且 aa' 不与 b,cb,c 重合)。
    • cc 关于 bb 对称跳到 c=2bcc'=2b-c(必须 cac' \ne acbc' \ne b,且 cc' 不与 a,ba,b 重合)。

    此外,如果 aabb 的距离小于 bbcc 的距离,则 aa 可以跳;如果 ccbb 的距离小于 bbaa 的距离,则 cc 可以跳。换句话说,只有两端的棋子能往中间跳?不是,两端的棋子可以跳过中间的棋子往更外侧跳,也可以往内侧跳,但往内侧跳必须保证中间有足够空间(即跳过中间棋子后不会落到另一个棋子上)。

    经过分析,题目的操作实际上是:设 d1=ba, d2=cbd_1 = b-a,\ d_2 = c-b

    • 如果 d1<d2d_1 < d_2,则 aa 可以跳到 bb 另一侧,新位置 a=b+d1=2baa' = b + d_1 = 2b-a,此时三个位置变为 b,a,cb, a', c(重新排序后为 b,c,ab, c, a'b,a,cb, a', c 取决于 aa'cc 的大小)。
    • 如果 d2<d1d_2 < d_1,则 cc 可以跳到 bb 另一侧,新位置 c=bd2=2bcc' = b - d_2 = 2b-c
    • 如果 d1=d2d_1 = d_2,则两端棋子都不能跳(因为跳后会与另一棋子重合)。

    实际上,这个游戏可以建模为一个二叉树结构,状态之间的转移可以看作在树上移动。初始状态和目标状态有公共祖先(根)时才有解。

本题关键: 将三颗棋子的位置 (a,b,c)(a,b,c) 看作一个状态,定义其父亲状态为将中间棋子往两边对称跳的逆操作(即把两端棋子往中间跳一步得到的状态)。这样所有状态形成了一棵无限深度的二叉树。问题转化为求初始状态和目标状态在这棵树上的距离。


输入格式

第一行包含三个整数,表示当前棋子的位置 a,b,ca, b, c(不一定有序,但互不相同)。
第二行包含三个整数,表示目标位置 x,y,zx, y, z(互不相同)。


输出格式

如果无解,输出一行 NO
如果可以到达,第一行输出 YES,第二行输出最少步数。


样例

输入样例 1

1 2 3
0 3 5

输出样例 1

YES
2

样例解释

初始:(1,2,3)(1,2,3),排序后 [1,2,3][1,2,3]d1=1,d2=1d_1=1,d_2=1,相等,两端都不能跳?但样例却说可以到达,说明我的理解有误。重新读题:“任意选一颗棋子,对一颗中轴棋子跳动。”意味着任何一颗棋子都可以作为跳动的棋子,任何另一颗棋子可以作为中轴,只要跳动后距离不变且只跳过一颗棋子。

(1,2,3)(1,2,3) 为例:

  • a=1a=1,以 b=2b=2 为中轴,跳到 2+(21)=32+(2-1)=3,但 33 已有棋子,不允许(每个点不能超过一个棋子)。
  • a=1a=1,以 c=3c=3 为中轴,跳到 3+(31)=53+(3-1)=51133 之间隔着 22,跳过了一颗棋子 22,且 55 没有棋子,允许。操作后位置为 (5,2,3)(5,2,3),排序为 2,3,52,3,5
  • b=2b=2,以 a=1a=1 为中轴,跳到 1(21)=01-(2-1)=02211 之间没有其他棋子?不,规则是“一次只允许跳过一颗棋子”,这里 22 关于 11 对称跳到 00,跳过了 11 吗?2200 之间只有 11,所以是跳过了一颗棋子,允许。操作后位置为 (1,0,3)(1,0,3),排序为 0,1,30,1,3
  • b=2b=2,以 c=3c=3 为中轴,跳到 3+(32)=43+(3-2)=42233 之间没有其他棋子?跳过了一颗棋子 33,允许。操作后位置为 (1,4,3)(1,4,3),排序为 1,3,41,3,4
  • c=3c=3,以 a=1a=1 为中轴,跳到 1(31)=11-(3-1)=-1,跳过了一颗棋子 22331-1 之间经过 1122,但只跳过 11?实际上 33 关于 11 对称,3311 距离 22,对称点 1-111 距离 22,中间没有其他棋子,允许。操作后位置为 (1,2,1)(1,2,-1),排序为 1,1,2-1,1,2
  • c=3c=3,以 b=2b=2 为中轴,跳到 2(32)=12-(3-2)=1,但 11 已有棋子,不允许。

因此从 (1,2,3)(1,2,3) 一步可以到达的状态有:(0,1,3)(0,1,3)(1,3,4)(1,3,4)(1,1,2)(-1,1,2)(2,3,5)(2,3,5) 等。

目标 (0,3,5)(0,3,5) 排序后为 (0,3,5)(0,3,5)
(1,2,3)(1,2,3)(0,3,5)(0,3,5) 的最少步数为 22,路径可以是:

  • (1,2,3)(0,1,3)(1,2,3) \to (0,1,3)(移动 202\to0
  • (0,1,3)(0,3,5)(0,1,3) \to (0,3,5)(移动 151\to5353\to5?检查:(0,1,3)(0,1,3) 中,移动 11 关于 00 中轴跳到 1-1 不行(无棋子跳过?),移动 11 关于 33 中轴跳到 553+(31)=53+(3-1)=5,跳过棋子 33,允许。得到 (0,3,5)(0,3,5)。 所以两步可达。

数据范围

  • 输入整数的绝对值不超过 10910^9
  • 保证 a,b,ca,b,c 互不相同,x,y,zx,y,z 互不相同。

时间限制:1000 ms
内存限制:524288 KB


提示

本题可以转化为树上的距离问题

将三颗棋子的位置排序为 (l,m,r)(l,m,r),记 d1=ml, d2=rmd_1=m-l,\ d_2=r-m。不妨设 d1d2d_1 \le d_2(否则对称处理)。

定义状态的父亲操作:将 rr 向左跳,即 rr 关于 mm 对称跳到 r=2mrr' = 2m-r,则新状态为 (l,m,r)(l,m,r') 重新排序。这相当于把右端点往中间跳一步。如果 d1=d2d_1 = d_2,则没有父亲(根状态)。

这样每个状态最多有一个父亲(因为只能将较长边的一端往中间跳),但可能有多个儿子(将两端往外跳)。所有状态形成了一棵二叉树(或称为“跳跳树”)。

两个状态有解当且仅当它们在同一个树上(即根状态相同)。根状态是 d1=d2d_1 = d_2 的状态,即等差数列,不能再往中间跳。

算法步骤:

  1. 将初始状态 SS 和目标状态 TT 分别向根状态跳跃,记录路径和深度。
  2. 如果根状态不同,则无解(输出 NO)。
  3. 否则,求 SSTT 的 LCA(最近公共祖先)在树上的深度,距离为 depth[S]+depth[T]2×depth[LCA]depth[S] + depth[T] - 2 \times depth[LCA]
  4. 向根跳跃的过程可以用类似辗转相除的方法加速,因为一次可以跳多步(当 d1d2d_1 \ll d_2 时,可以连续跳很多步直到 d1d2d_1 \ge d_2)。

具体实现时,定义一个函数 jump(state, k) 返回从状态向上跳 kk 步后的状态,如果不足 kk 步则跳到根并返回实际步数。然后通过二分或计算的方式求 LCA 的深度。

时间复杂度:每次跳跃类似辗转相除,O(logmax{坐标})O(\log \max\{坐标\})