将三颗棋子看作三元组 ((x,y,z) x<y<z),得其能转移到的状态有:
[largeegin{aligned}
&(2x-y,x,z) \
&(x,z,2z-y) \
&(x,2y-z,y) (y-x>z-y) \
&(y,2y-x,z) (y-x<z-y) \
end{aligned}
]
后两个转移只会满足其中一个,那么将中间棋子向两边跳看作左右儿子,两边棋子向中间跳看作父亲,根节点为满足 (y-x=z-y) 的状态,那么每个状态都唯一对应一棵二叉树。
到树上的 (lca) 即为最小步数,可以通过除来加快跳父亲的过程,然后二分找 (lca) 即可。
#include<bits/stdc++.h>
#define inf 1000000000
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int dep;
struct node
{
int x,y,z;
void init()
{
read(x),read(y),read(z);
int a[3]={x,y,z};
sort(a,a+3),x=a[0],y=a[1],z=a[2];
}
}s,t;
bool operator == (const node &a,const node &b)
{
return a.x==b.x&&a.y==b.y&&a.z==b.z;
}
node find(node p,int d,int goal)
{
int x=p.x,y=p.y,z=p.z,d1=y-x,d2=z-y;
if(d==goal||d1==d2)
{
dep=d;
return p;
}
if(d1>d2)
{
swap(d1,d2);
int v=min(d2/d1-(d2%d1==0),goal-d);
return find((node){x,y-v*d1,z-v*d1},d+v,goal);
}
int v=min(d2/d1-(d2%d1==0),goal-d);
return find((node){x+v*d1,y+v*d1,z},d+v,goal);
}
int calc()
{
int d1,d2,val,l=0,r=inf,dis;
find(s,0,inf),d1=dep,find(t,0,inf),d2=dep;
if(d1>d2) s=find(s,0,d1-d2);
else t=find(t,0,d2-d1);
while(l<=r)
{
int mid=(l+r)>>1;
if(find(s,0,mid)==find(t,0,mid)) dis=mid,r=mid-1;
else l=mid+1;
}
return abs(d1-d2)+dis*2;
}
int main()
{
s.init(),t.init();
if(find(s,0,inf)==find(t,0,inf)) printf("YES
%d",calc());
else puts("NO");
return 0;
}