解析
考虑一个三元组
(
x
,
y
,
z
)
(x,y,z)
(x,y,z),看它能如何跳
要么是
y
y
y往左右跳,左右边界会变大
要么是两边往中间跳,由于最多跨过一个棋子,所以左右边界会变小
当三点等距时,无法往中间跳
于是我们惊喜的发现:可以互相转移的状态形成了一个二叉树形结构!!!
往中间跳的时候,相当于跳父亲;往两边跳相当于跳儿子
当且仅当两个状态的根相同时,有解
又由于这个跳的操作是可逆的,所以我们的问题就可以转化为两个点在树上的距离
于是我们就可以用类似倍增求LCA的思路解决本题
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e6+100;
const double eps=1e-6;
const int mod=1333331;
inline ll read(){
ll x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return f*x;
}
int n,m,p;
struct node{
ll a,b,c;
inline void solve(){
if(b>c) swap(b,c);
if(a>b) swap(a,b);
if(b>c) swap(b,c);
return;
}
bool operator == (const node u)const{return a==u.a&&b==u.b&&c==u.c;}
bool operator != (const node u)const{return a!=u.a||b!=u.b||c!=u.c;}
}u,v;
node walk(node o,ll lft){
if(lft==0) return o;
ll d1=o.b-o.a,d2=o.c-o.b;
if(d1==d2) return o;
if(d1<d2){
int k=min((d2-1)/d1,lft);
o.a+=k*d1,o.b+=k*d1;
return walk(o,lft-k);
}
else{
int k=min((d1-1)/d2,lft);
o.b-=k*d2;o.c-=k*d2;
return walk(o,lft-k);
}
}
int dep(node o){
int st=0,ed=2e9;
while(st<ed){
int mid=(st+ed)>>1;
if(walk(o,mid+1)==walk(o,mid)) ed=mid;
else st=mid+1;
}
return st;
}
void print(node o){
printf("(%lld %lld %lld)\n",o.a,o.b,o.c);return;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
u=(node){read(),read(),read()};
v=(node){read(),read(),read()};
u.solve(),v.solve();
if(walk(u,2e9)!=walk(v,2e9)) printf("NO\n");
else{
printf("YES\n");
int aa=dep(u),bb=dep(v);
if(aa<bb) swap(u,v);
int num=abs(aa-bb);
int ans=num;
for(int k=30;k>=0;k--){
if(num>=(1<<k)) u=walk(u,1<<k),num-=(1<<k);
}
if(u==v){
printf("%d\n",ans);return 0;
}
//printf("-- ans=%d\n",ans);
//print(u);print(v);
for(int k=30;k>=0;k--){
node uu=walk(u,1<<k),vv=walk(v,1<<k);
if(uu==vv) continue;
u=uu;v=vv;ans+=(1<<(k+1));
}
printf("%d\n",ans+2);
}
return 0;
}
/*
4a
1 2
2 3
1 3
3 4
*/