AC链接
神题一道,反正蒟蒻乱搞拿了25分…
举一个栗子:
-10 -9 7
分析一下这个栗子:
从 (−10,−9,7) 棋子向两边跳可以到 (−11,−10,7) , (−25,−10,−9)
令 dis=−9−(−10)=1,dis2=7−(−9)=16 ,由于 dis<dis2 ,我们让左边的棋子往中间跳可以到 (−9,−8,7)
这样我们就可以建立一棵二叉树辣。
往两边跳的状态为左右儿子,往中间跳的状态为父亲。
这样就变成了查找树的两个节点之间的距离辣。
由于这棵树是不可能建立出来的,所以采用二分查找最近公共祖先的方法。
令dfs(node a,int k,int &res)表示状态a经过k次后到达的状态,res为实际走的次数。
向父亲状态的转移就推一推就行辣…
#include
#include
#include
using namespace std;
const int inf=0x3f3f3f3f;
struct node
{
int num[4];
void work(){sort(num+1,num+4);};
bool operator != (const node &a)const
{return num[1]!=a.num[1]||num[2]!=a.num[2]||num[3]!=a.num[3];}
}st, en;
node dfs(node &a,int k,int &cnt)
{
int dis=a.num[2]-a.num[1], dis2=a.num[3]-a.num[2];
if(dis==dis2)return a;
node ans=a;
int t;
if(dis>dis2)
{
t=min(k,(dis-1)/dis2);
k-=t, cnt+=t, ans.num[2]-=t*dis2, ans.num[3]-=t*dis2;
}
else
{
t=min(k,(dis2-1)/dis);
k-=t, cnt+=t, ans.num[2]+=t*dis, ans.num[1]+=t*dis;
}
if(k)return dfs(ans,k,cnt);
return ans;
}
int main()
{
//freopen("hop.in","r",stdin);
//freopen("hop.out","w",stdout);
for(int i=1;i<=3;++i)scanf("%d",&st.num[i]);
for(int i=1;i<=3;++i)scanf("%d",&en.num[i]);
st.work(), en.work();
int res=0, res2=0;
node a=dfs(st,inf,res), b=dfs(en,inf,res2);
if(a!=b)puts("NO");
else
{
puts("YES");
if(res>res2)swap(res,res2), swap(st,en);
int ans=res2-res, tmp, l=0, r=res, mid;
en=dfs(en,ans,tmp);
while(l<=r)
{
mid=(l+r)>>1;
if(dfs(st,mid,tmp)!=dfs(en,mid,tmp))l=mid+1;
else r=mid-1;
}
printf("%d\n",ans+l+l);
}
return 0;
}