hdu 3830 Checkers 二分答案查找最近公共祖先

Problem Description
Little X, Little Y and Little Z are playing checkers when Little Y is annoyed. So he wants to make the chessboard much bigger. Although Little Z insists the original version, Little X stands by Little Y. After they enlarge the chessboard, the chessboard turns to an infinite line. 
The chessboard is like the Number Axes now, with each integer point able to hold a checker. At initial status there are three checkers on three different integer points , and through the game there always are three checkers. Every time, they can choose a checker A to jump across a pivot checker B to a new position(but the distance between old A and B equals to new A and B, and there should be no other checkers except B in the range [old A, new A]).
After playing for a while, they wonder whether an given status a,b,c can be transferred to x,y,z. obeying the rules. Since the checkers are considered the same, it is unnecessary for a must jump to x. 
 

Input
The first line is a,b,c.
The second line is x,y,z.
They are all integers in range (-10^9, 10^9) and the two status are valid.
 

Output
The first line is YES or NO, showing whether the transfer can be achieved.
If it is YES, then output the least steps in the second line.
 

Sample Input
   
   
   
   
1 2 3 0 3 5
 

Sample Output
   
   
   
   
YES 2
Hint
The middle checker jumps to position 0, and the status is 0 1 3 Then , the middle one jumps to 5.

//



#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
//向中间走类似向根节点走,向两边走类似向二叉树左右走
//y-x=z-y 树根
struct State
{
    long long x,y,z,d;//x<y<z;  d为到根节点的距离,初始化为0
    void init()
    {
        d=0;
        if(x>y) swap(x,y);
        if(x>z) swap(x,z);
        if(y>z) swap(y,z);
    }
};
bool Equal(const State &a,const State &b)//不用判断d
{
    if(a.x==b.x&&a.y==b.y&&a.z==b.z) return true;
    return false;
}
State Root(State &a)//找a的根节点并计算出a到根节点的距离
{
    State cnt=a;
    long long l=cnt.y-cnt.x,r=cnt.z-cnt.y;
    while(l!=r)//l=r时到树根
    {
        long long t;
        if(l<r)//右面区间大,x、y向右走
        {
            if(r%l==0) t=r/l-1;
            else t=r/l;
            cnt.x+=t*l;
            cnt.y+=t*l;
        }
        else
        {
            if(l%r==0) t=l/r-1;
            else t=l/r;
            cnt.z-=t*r;
            cnt.y-=t*r;
        }
        a.d+=t;
        l=cnt.y-cnt.x,r=cnt.z-cnt.y;
    }
    return cnt;
}
State stateUp(const State &a,long long step)//a状态向上走step步,step<=a.d
{
    State cnt=a;
    cnt.d=a.d-step;
    long long l=cnt.y-cnt.x,r=cnt.z-cnt.y;
    while(step>0)
    {
        long long t;
        if(l<r)//右面区间大,x、y向右走
        {
            if(r%l==0) t=r/l-1;
            else t=r/l;
            if(t>step) t=step;
            cnt.x+=t*l;
            cnt.y+=t*l;
        }
        else
        {
            if(l%r==0) t=l/r-1;
            else t=l/r;
            if(t>step) t=step;
            cnt.z-=t*r;
            cnt.y-=t*r;
        }
        step-=t;
        l=cnt.y-cnt.x,r=cnt.z-cnt.y;
    }
    return cnt;
}
int main()
{
    State st,ed;
    while(scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&st.x,&st.y,&st.z,&ed.x,&ed.y,&ed.z)==6)
    {
        st.init();ed.init();//初始化
        State stRoot=Root(st);
        State edRoot=Root(ed);
        //st和ed根不相同
        if(!Equal(stRoot,edRoot))
        {
            printf("NO\n");
            continue;
        }
        //st和ed根相同
        //二分答案查找st和ed的最近公共祖先
        //首先把两初始状态调整到一个深度
        long long res=st.d-ed.d>0?st.d-ed.d:ed.d-st.d;
        if(st.d>ed.d) st=stateUp(st,res);
        else ed=stateUp(ed,res);
        //二分答案
        long long l=0,r=st.d;
        while(l<r)
        {
            long long mid=(l+r)/2;
            if(Equal(stateUp(st,mid),stateUp(ed,mid))) r=mid;
            else l=mid+1;
        }
        printf("YES\n%I64d\n",res+2*r);//answer=res+2*r
    }
    return 0;
}

你可能感兴趣的:(hdu 3830 Checkers 二分答案查找最近公共祖先)