BZOJ2144 【国家集训队】跳跳棋(建模+ 二分 + LCA)

xiaoxiao2025-05-14  39

任重而道远

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的

游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋

子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只

允许跳过1颗棋子。

写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

Input

第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)

第二行包含三个整数,表示目标位置x y z。(互不相同)

Output

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

Sample Input

1 2 3

0 3 5

Sample Output

YES

2

【范围】 100% 绝对值不超过10^9

AC代码:

#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int oo = 1e9; struct Node { int a, b, c; bool operator != (const Node &nd) const { return a != nd.a || b != nd.b || c != nd.c; } }u, v; int tot, dep1, dep2, a[5]; Node cal (Node nd, int k) { int d1 = nd.b - nd.a, d2 = nd.c - nd.b; if (d1 == d2) return nd; if (d1 < d2) { int x = min (k, (d2 - 1) / d1); k -= x, tot += x; nd.a += x * d1, nd.b += x * d1; } else { int x = min (k, (d1 - 1) / d2); k -= x, tot += x; nd.c -= x * d2, nd.b -= x * d2; } if (k) return cal (nd, k); else return nd; } int main () { scanf ("%d%d%d", &a[1], &a[2], &a[3]); sort (a + 1, a + 4); u = (Node) {a[1], a[2], a[3]}; scanf ("%d%d%d", &a[1], &a[2], &a[3]); sort (a + 1, a + 4); v = (Node) {a[1], a[2], a[3]}; Node rt1 = cal (u, oo); dep1 = tot, tot = 0; Node rt2 = cal (v, oo); dep2 = tot, tot = 0; if (rt1 != rt2) { puts ("NO"); return 0; } else puts ("YES"); if (dep1 < dep2) swap (dep1, dep2), swap (u, v); int delta = dep1 - dep2; u = cal (u, delta); int l = 0, r = dep2; while (l <= r) { int mid = l + r >> 1; if (cal (u, mid) != cal (v, mid)) l = mid + 1; else r = mid - 1; } printf ("%d", delta + l * 2); return 0; }

 

转载请注明原文地址: https://www.6miu.com/read-5030109.html

最新回复(0)