Description
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。
我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)
跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。
写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。
Data Constraint
20% 输入整数的绝对值均不超过10
40% 输入整数的绝对值均不超过10000
100% 绝对值不超过10^9
Solution
很神奇的一道题
首先给123棋子排序,设中间棋子为p,前1、2棋子距离为d1,2、3棋子为d2,那么分类如下:
d1 < d2,根据题意可以把棋子1跳到棋子2、3中间位置
d1 = d2,我们不能把两边的棋子再往中间跳了
d1 > d2,类似地可以把棋子3跳到棋子1、2中间位置
把三种情况都视为二叉树上节点,d1=d2作为一棵二叉树的根节点,那么题意转为求树上两点最短路,进而想到lca
对于无解的情况把一个状态暴力向上跳INF找到根,比较两个根即可
对于100%的数据可以把辗转相减用相除加速,这样复杂度就是log级别的了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define min(x,y) ((x)<(y)?(x):(y))
const int INF=0x7777777f;
struct pos{
int p,d1,d2;
bool operator ==(pos b) {return b.p==p&&b.d1==d1&&b.d2==d2;}
}a,b;
int ta[3],tb[3];
int get_dep(pos now) {
if (now.d1==now.d2) return 0;
if (now.d1<now.d2) return (now.d2-1)/now.d1+get_dep((pos){now.p+now.d2-(now.d2-1)%now.d1,now.d1,(now.d2-1)%now.d1+1});
else return (now.d1-1)/now.d2+get_dep((pos){now.p-now.d1+(now.d1-1)%now.d2,(now.d1-1)%now.d2+1,now.d2});
}
void up(pos &now,int k) {
while (k) {
if (now.d1==now.d2) return;
if (now.d1<now.d2) {
int tmp=min(k,(now.d2-1)/now.d1);
k-=tmp;
now=(pos){now.p+tmp*now.d1,now.d1,now.d2-tmp*now.d1};
} else {
int tmp=min(k,(now.d1-1)/now.d2);
k-=tmp;
now=(pos){now.p-tmp*now.d2,now.d1-tmp*now.d2,now.d2};
}
}
}
int main(void) {
rep(i,0,2) scanf("%d",&ta[i]);
std:: sort(ta,ta+3); a=(pos){ta[1],ta[1]-ta[0],ta[2]-ta[1]};
rep(i,0,2) scanf("%d",&tb[i]);
std:: sort(tb,tb+3); b=(pos){tb[1],tb[1]-tb[0],tb[2]-tb[1]};
pos root_a=a; up(root_a,INF);
pos root_b=b; up(root_b,INF);
if (!(root_a==root_b)) {
puts("NO");
return 0;
}
int dep_a=get_dep(a);
int dep_b=get_dep(b);
int ans=dep_a+dep_b;
if (dep_a<dep_b) {std:: swap(dep_a,dep_b); std:: swap(a,b);}
up(a,dep_a-dep_b); dep_a=dep_b;
drp(i,30,0) {
int k=1<<i;
if (k<=dep_a) {
pos tmp_a=a;
pos tmp_b=b;
up(tmp_a,k); up(tmp_b,k);
if (!(tmp_a==tmp_b)) {
a=tmp_a;
b=tmp_b;
dep_a-=k;
}
}
}
if (!(a==b)) {up(a,1); up(b,1);}
printf("YES\n%d\n",ans-2*get_dep(a));
return 0;
}