hdu-3830(奇妙的想法+LCA+二分)

Checkers

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others)
Total Submission(s): 1519    Accepted Submission(s): 453


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.
 
题意:一个人在玩跳棋,只有三个棋子,在一条数轴上,要求从初态到末态最少需要的步数,而规则则是这样的:一个棋子可以以另一棋子为垫子,跳到另一棋子对面,设一开始两棋子位置为x、y,跳完后为y、x1,则有x1-y==y-x。而且这里还有一个要求,就是跳跃过程中不能越过第三个棋子进行跳跃。

题解:仔细思考不难发现,其实每种棋子状态都可以一直往内跳直到无法再跳为止,然后就可以想到,对于初态和末态,如果两者都往内跳直到最后得到的根如果相同,就说明两者可以互相到达,如果根不同,则无法到达,这就解决了“YES”和“NO”的问题了。接下来在“YES”的情况下,我们要求其最小步数,我们可以先将两者到根的所需的步数统一一下,将需要步数多的先跳许多步到达和另一个一样需要相同步数到达根,然后对步数二分,只要对于当前枚举的步数,两者求得的终态相同,就令右端点为当前枚举值,反之相反。

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <functional>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn = 5e3+7;
int a,b,c;
int x,y,z;

struct node{
    int x,y,z;
    node(){}
    node(int _x,int _y,int _z){
        if(_x>_y) swap(_x,_y);
        if(_x>_z) swap(_x,_z);
        if(_y>_z) swap(_y,_z);
        x = _x,y = _y,z = _z;
    }
    bool operator == (node a){
        if(a.x==x&&a.y==y&&a.z==z) return 1;
        else return 0;
    }
    bool operator != (node a){
        if(a.x==x&&a.y==y&&a.z==z) return 0;
        else return 1;
    }
};

node fin(node a,int &cnt){
    while(1){
        if(a.y-a.x < a.z-a.y){
            int tim;
            if((a.z-a.y)%(a.y-a.x)==0){
                tim = (a.z-a.y)/(a.y-a.x)-1;
            }
            else tim = (a.z-a.y)/(a.y-a.x);
            cnt+=tim;
            a = node(a.y+tim*(a.y-a.x),a.y+(tim-1)*(a.y-a.x),a.z);
        }
        else if(a.z-a.y < a.y-a.x){
            int tim;
            if((a.y-a.x)%(a.z-a.y)==0){
                tim = (a.y-a.x)/(a.z-a.y)-1;
            }
            else tim = (a.y-a.x)/(a.z-a.y);
            cnt+=tim;
            a = node(a.x,a.y-tim*(a.z-a.y),a.y-(tim-1)*(a.z-a.y));
        }
        else break;
    }
    return a;
}
node u,v;
node did(node a,int cnt){
    while(cnt>0){
        if(a.y-a.x < a.z-a.y){
            int tim;
            if((a.z-a.y)%(a.y-a.x)==0){
                tim = (a.z-a.y)/(a.y-a.x)-1;
            }
            else tim = (a.z-a.y)/(a.y-a.x);
            tim = min(cnt,tim);
            a = node(a.y+tim*(a.y-a.x),a.y+(tim-1)*(a.y-a.x),a.z);
            cnt-=tim;
        }
        else if(a.z-a.y < a.y-a.x){
            int tim;
            if((a.y-a.x)%(a.z-a.y)==0){
                tim = (a.y-a.x)/(a.z-a.y)-1;
            }
            else tim = (a.y-a.x)/(a.z-a.y);
            tim = min(cnt,tim);
            a = node(a.x,a.y-tim*(a.z-a.y),a.y-(tim-1)*(a.z-a.y));
            cnt-=tim;
        }
    }
    return a;
}

void solve(){
    int sum1 = 0,sum2 = 0;
    if(fin(u,sum1)!=fin(v,sum2)){
        puts("NO");
        return;
    }
    else puts("YES");
    if(sum1<sum2){
        v = did(v,sum2-sum1);
    }
    else{
        u = did(u,sum1-sum2);
    }
    int l = 0,r = min(sum1,sum2);
    while(r-l>1){
        int mid = (l+r)>>1;
        if(did(u,mid)==did(v,mid)){
            r = mid;
        }
        else l = mid;
    }
    if(did(u,l)==did(v,l)){
        cout<<abs(sum1-sum2)+2*l<<endl;
    }
    else cout<<abs(sum1-sum2)+2*r<<endl;
    return;
}

int main(){
    while(scanf("%d %d %d",&a,&b,&c)!=EOF){
        u = node(a,b,c);
        scanf("%d %d %d",&x,&y,&z);
        v = node(x,y,z);
        solve();
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值