作为紫题却是一道巨大神的人类智慧题,由于智商不足所以看了题解……
观察跳棋的性质,我们发现中间的棋子可以通过向两边跳扩张区间,两边的棋子最多有一个能通过向中间跳缩小区间,并且最后会缩成两边的棋子关于中间对称的形态。
先解决判定无解的问题。由于一个区间向外可以扩张成两个,向内可以缩小成一个,我们利用缩小的唯一性,看两个状态不断缩小时是否有交集即可。
然后最优解可以直接加一个二分。
但是这样你发现会 T 飞,我们不能每次只跳一步。发现有些步数可以用取模优化掉,最终复杂度变成了辗转相除一样的东西,可以通过此题。
如果你还是理解不了上面的过程,这里给出另一种理解方式:把扩张想象成儿子,缩小想象成父亲,这样就是一棵二叉树,答案就是树上路径的距离。
int ans;
struct Tri {
int a,b,c;
void S(){
if(a>b)swap(a,b);
if(a>c)swap(a,c);
if(b>c)swap(b,c);
}
}A,B;
bool operator == (Tri A,Tri B){
return A.a==B.a&&A.b==B.b&&A.c==B.c;
}
il Tri Get(Tri _A,int &stp){//get final status
Tri A=_A;A.S();
while(A.b-A.a!=A.c-A.b){
int lt=A.b-A.a,rt=A.c-A.b;
if(lt<rt){//a jumps over b
int q=rt/lt,r=rt%lt;
if(!r)r=lt,q--;
A.a+=rt-r,A.b+=rt-r,stp+=q;
}else {//c jumps over b
int q=lt/rt,r=lt%rt;
if(!r)r=rt,q--;
A.c-=lt-r,A.b-=lt-r,stp+=q;
}
}
return A;
}
il Tri Check(Tri _A,int lmt){
Tri A=_A;A.S();
while(lmt>0){
int lt=A.b-A.a,rt=A.c-A.b;
if(lt<rt){//a jumps over b
int q=rt/lt,r=rt%lt;
if(!r)r=lt,q--;
if(q>lmt)q=lmt;
A.a+=q*lt,A.b+=q*lt,lmt-=q;
}else {//c jumps over b
int q=lt/rt,r=lt%rt;
if(!r)r=rt,q--;
if(q>lmt)q=lmt;
A.c-=q*rt,A.b-=q*rt,lmt-=q;
}
}
return A;
}
int main(){
Read(A.a),Read(A.b),Read(A.c);
Read(B.a),Read(B.b),Read(B.c);
A.S(),B.S();
int stpa=0,stpb=0;
if(!(Get(A,stpa)==Get(B,stpb)))return puts("NO"),0;
int d;
if(stpa<stpb)d=stpb-stpa,B=Check(B,d);
else d=stpa-stpb,A=Check(A,d);
int l=0,r=min(stpa,stpb);
while(l<=r){
int m=nmid;Tri _A=Check(A,m),_B=Check(B,m);
if(_A==_B)ans=m,r=m-1;
else l=m+1;
}
cout<<"YES"<<endl<<ans+ans+d<<endl;
KafuuChino HotoKokoa
}