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 <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#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<dis2) t=min(k,(dis2-1)/dis1),k-=t,dep+=t,u.a+=t*dis1,u.b+=t*dis1;
    else t=min(k,(dis1-1)/dis2),k-=t,dep+=t,u.b-=t*dis2,u.c-=t*dis2;
    if (k) return find(u,k,dep); else return u;
}

il void work(){
    for (RG int i=1;i<=3;++i) a[0][i]=gi();sort(a[0]+1,a[0]+4); for (RG int i=1;i<=3;++i) a[1][i]=gi();sort(a[1]+1,a[1]+4);
    data x=(data){a[0][1],a[0][2],a[0][3]},y=(data){a[1][1],a[1][2],a[1][3]},u=find(x,inf,depa),v=find(y,inf,depb);
    if (u!=v){ puts("NO"); return; } puts("YES"); if (depa<depb) swap(x,y),swap(depa,depb);
    RG int l=0,r=depb,mid,cnt,ans,Ans=depa-depb; x=find(x,Ans,cnt);
    while (l<=r){
	mid=(l+r)>>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;
}

發佈了49 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章