P1852 [国家集训队]跳跳棋

P1852 [国家集训队]跳跳棋

题目背景

原《奇怪的字符串》请前往 P2543

题目描述

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。

我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)

跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。

写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

输入格式

第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)

第二行包含三个整数,表示目标位置x y z。(互不相同)

输出格式

如果无解,输出一行NO。

如果可以到达,第一行输出YES,第二行输出最少步数。

输入输出样例

输入 #1
1 2 3
0 3 5
输出 #1
YES
2

说明/提示

20% 输入整数的绝对值均不超过10

40% 输入整数的绝对值均不超过10000

100% 绝对值不超过10^9

 

 

#include<bits/stdc++.h>
#define LL long long
const LL INF=1e10;
using namespace std;
struct Q{int x,y,z;};
LL res;
bool operator != (Q a,Q b){
    return a.x!=b.x||a.y!=b.y||a.z!=b.z;
}
Q Get(Q a,LL k){
    res=0;
    while(k){
        int t1=a.y-a.x,t2=a.z-a.y;
        if(t1==t2) return a;
        if(t1<t2){
            int tmp=(int)min(k,(LL)(t2-1)/t1);
            k-=tmp;res+=tmp;
            a.x+=tmp*t1;a.y+=tmp*t1;
        }
        else{
            int tmp=(int)min(k,(LL)(t1-1)/t2);
            k-=tmp;res+=tmp;
            a.y-=tmp*t2;a.z-=tmp*t2;
        }
    }
    return a;
}
int a[3];
int main(){
    //freopen("nt2011_hop.in","r",stdin);freopen("nt2011_hop.out","w",stdout);
    Q s,t;int d1,d2,ans;
    for(int i=0;i<3;i++) scanf("%d",&a[i]);
    sort(a,a+3);
    s=(Q){a[0],a[1],a[2]};
    for(int i=0;i<3;i++) scanf("%d",&a[i]);
    sort(a,a+3);
    t=(Q){a[0],a[1],a[2]};
    Q t1=Get(s,INF);d1=res;
    Q t2=Get(t,INF);d2=res;
    if(t1!=t2){puts("NO");return 0;}
    puts("YES");
    if(d1<d2){
        ans=d2-d1;t=Get(t,d2-d1);
    }
    else{
        ans=d1-d2;s=Get(s,d1-d2);
    }
    LL l=0,r=INF,mid;
    while(l!=r){
        mid=(l+r)>>1;
        if(Get(s,mid)!=Get(t,mid)) l=mid+1;
        else r=mid;
    }    
    printf("%lld\n",l*2+ans);
    return 0;
}

posted @ 2019-08-09 15:06  DreamingBligo_Tido  阅读(163)  评论(0编辑  收藏  举报