BZOJ2144 國家集訓隊 跳跳棋

2022-05-19 19:08:30 字數 2392 閱讀 5764

跳跳棋是在一條數軸上進行的。棋子只能擺在整點上。每個點不能擺超過乙個棋子。

我們用跳跳棋來做乙個簡單的遊戲:棋盤上有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

分析

這個題目是真的蛇皮,沒話講。

本題是一道lca加二分的題目,以我的智商是看不出來的。

下面就來說一下我在sac大佬的幫助下怎麼分析的吧。

設最左邊的棋子為a,中間棋子為b,最右邊的棋子為c。

顯而易見只有三種跳躍方式。

1.b往左邊跳。

2.b往右邊跳。

3.離b近的往裡跳(離b遠的不可以跳,因為會越過兩個棋子)。

當a,c距離和b一樣時,就把當前狀態設為a,b,c的起始狀態,而且a,b,c的起始狀態只有一種。

所以判斷一下a,b,c起始狀態和不和x,y,z的起始狀態一不一樣就行了。

怎麼判斷呢?

顯然,兩個棋子往中間跳才可以回到起始狀態。

但是,如果純模擬的話就又會超時。

比如1,2,100000000。

這樣就會進行很多次操作。

此時,設d1=b-a,d2=c-b。

d1小於d2時我們移動a,然後會發現d1沒變,d2減小了d1所以我們可以連續走d2/d1次,反之亦然,此時d2小於d1了換個方向走。注意:d2%d1等於0時走d2/d1-1步就到根了。

然後怎麼判斷要走多少步呢?

列舉顯然不行。

那就二分吧。

如果當前二分得到的mid可以使他們狀態相同。

縮小上界,否則擴大下界,下面就貼上**了(自認為寫的很清楚)

#include#include

#include

using

namespace

std;

typedef

long

long

ll;void sot(ll &a,ll &b,ll &c)

ll min(ll x,ll y)

ll getfa(ll a,ll b,ll c,ll &dep,ll &d)

else

}else

else}}

dep=0

; d=d1;

returna;}

void fa(ll &a,ll &b,ll &c,ll step)

else

}else

else}}

}int

main()

else

else

}ll l=0,r=min(dep1,dep2),ans=0

;

while(l<=r)

cout

<

yes"

<

cout

<2+len;

}

bzoj2144 國家集訓隊2011 跳跳棋

跳跳棋是在一條數軸上進行的。棋子只能擺在整點上。每個點不能擺超過乙個棋子。我們用跳跳棋來做乙個簡單的遊戲 棋盤上有3顆棋子,分別在a,b,c這三個位置。我們要通過最少的跳動把他們的位置移動成x,y,z。棋子是沒有區別的 跳動的規則很簡單,任意選一顆棋子,對一顆中軸棋子跳動。跳動後兩顆棋子距離不變。一...

luogu P1852 國家集訓隊 跳跳棋

luogu 直接操作是不可能的,考慮發現一些性質.可以發現如果每次跳的棋子都是兩邊的,那麼最多只有一種方案,那麼就把這樣操作得到的狀態記為當前狀態的父親,從乙個狀態這樣做一定會結束.那麼如果兩個狀態只操作兩邊到達的最終狀態相同,那麼就可以互相轉換 步數的話,如果把這個看成一棵樹,那麼就是乙個樹上距離...

P1852 國家集訓隊 跳跳棋

原 奇怪的字串 請前往 p2543 跳跳棋是在一條數軸上進行的。棋子只能擺在整點上。每個點不能擺超過乙個棋子。我們用跳跳棋來做乙個簡單的遊戲 棋盤上有3顆棋子,分別在a,b,c這三個位置。我們要通過最少的跳動把他們的位置移動成x,y,z。棋子是沒有區別的 跳動的規則很簡單,任意選一顆棋子,對一顆中軸...