解析
考虑一个三元组(x,y,z)(x,y,z)(x,y,z),看它能如何跳
要么是yyy往左右跳,左右边界会变大
要么是两边往中间跳,由于最多跨过一个棋子,所以左右边界会变小
当三点等距时,无法往中间跳
于是我们惊喜的发现:可以互相转移的状态形成了一个二叉树形结构!!!
往中间跳的时候,相当于跳父亲;往两边跳相当于跳儿子
当且仅当两个状态的根相同时,有解
又由于这个跳的操作是可逆的,所以我们的问题就可以转化为两个点在树上的距离
于是我们就可以用类似倍增求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_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifu=(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;
}
/*4a1 22 31 33 4
*/