顶级大神题QAQ
完全没思路了这次。。
然后就去膜了题解。。感觉我很诚实啊
感觉真是神奇啊。。
我们先把棋子排序,这样好搞一点
首先,题目有要求,不可以跳过别人
那么这也就是说,两边的棋子只有一个是可以动的,但是中间向左向右跳都可以
当然,也有左右都不能动的情况
所以一个点就有三种扩展方式啦!
然后动的方式是可逆的,这个没有问题。。
于是问题可以想象为一棵树,向上跳是两旁的跳,然后儿子就是中间的跳
于是问题就转化为求树上两个点的距离
但是这题不是一颗树,是一个森林。。这个大家都知道吧,所有有NO的情况。。
然后求他的父亲的时候,要一次跳多个,要不太慢
就这样吧
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int MAX=1<<30;
struct qq
{
int x[5];
void read () {for (int u=1;u<=3;u++) scanf("%d",&x[u]);}
void Sort () {sort(x+1,x+4);}
bool operator != (const qq &a)const
{return x[1]!=a.x[1]||x[2]!=a.x[2]||x[3]!=a.x[3];};
}S,T;
int mymin (int x,int y){return x<y?x:y;}
qq cal (qq a,int k,int &ret)
{
qq ans=a;
int dis1=a.x[2]-a.x[1],dis2=a.x[3]-a.x[2];
/* for (int u=1;u<=3;u++) printf("%d ",a.x[u]);
printf("\n");*/
if (dis1==dis2)//到这一棵树的根了
return ans;
else if (dis1<dis2)//左边跳
{
int t=mymin(k,(dis2-1)/dis1);// -1 是避免跳重合了
k-=t;
ret+=t;
ans.x[2]+=t*dis1;
ans.x[1]+=t*dis1;
}
else
{
int t=mymin(k,(dis1-1)/dis2);
k-=t;
ret+=t;
ans.x[3]-=t*dis2;
ans.x[2]-=t*dis2;
}
if (k!=0) return cal(ans,k,ret);
return ans;
}
int main()
{
S.read();S.Sort();
T.read();T.Sort();
int lalal1=0,lalal2=0;
qq a=cal(S,MAX,lalal1),b=cal(T,MAX,lalal2);//这两个节点的深度
// printf("%d %d\n",lalal1,lalal2);
if (a!=b) {printf("NO");return 0;}//这两个点不在一棵树上,不可能有解
else
{
printf("YES\n");
if (lalal1>lalal2)
{
swap(lalal1,lalal2);
swap(S,T);
}//让T更深
int ans=lalal2-lalal1;//先跳到同一深度
int A;
T=cal(T,ans,A);
int l=0,r=lalal1,ans1;
while (l<=r)
{
int mid=(l+r)>>1;
if (cal(S,mid,A)!=cal(T,mid,A)) l=mid+1;
else {r=mid-1;ans1=mid;}
}
printf("%d\n",ans+ans1*2);
}
return 0;
}