bzoj2144 【国家集训队2011】跳跳棋

Description

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。 写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

Input

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

Output

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

Sample Input

1 2 3
0 3 5

Sample Output

YES
2

【范围】
100% 绝对值不超过10^9


正解:倍增lca

为了方便研究跳法,我们把棋子按坐标大小排序。我们发现,当中间那粒棋子与左边的距离和与右边的距离不相等时,有3种跳法,而两者距离相等时,只有两种跳法。所以,对于往中间跳的跳法,我们可以把它理解成在树上跳父亲,而对于往旁边跳,我们可以理解成在树上跳儿子。所以我们就可以把题意转化一下,即第一问为两种状态是否有lca,而第二种则是问两种状态在树上的距离。我们可以采用类似倍增的方法跳lca,来求出答案。


//It is made by wfj_2048~
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define inf 1<<30
#define il inline
#define RG register
#define ll long long

using namespace std;

struct data{
    int a,b,c;
    bool operator != (const data &x) const{
	return a!=x.a || b!=x.b || c!=x.c;
    }
};

int a[2][5],depa,depb;

il int gi(){
    RG int x=0,q=0; RG char ch=getchar();
    while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if (ch=='-') q=1,ch=getchar();
    while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q ? -x : x;
}

il data find(RG data u,RG int k,RG int &dep){
    RG int dis1=u.b-u.a,dis2=u.c-u.b,t; if (dis1==dis2) return u;
    if (dis1>1;
	RG data x1=find(x,mid,cnt),y1=find(y,mid,cnt);
	if (x1!=y1) l=mid+1; else ans=mid,r=mid-1;
    }
    printf("%d\n",Ans+2*ans); return;
}

int main(){
    work();
    return 0;
}

你可能感兴趣的:(倍增,lca)