BZOJ2144跳跳棋——LCA+二分
生活随笔
收集整理的這篇文章主要介紹了
BZOJ2144跳跳棋——LCA+二分
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題目描述
跳跳棋是在一條數(shù)軸上進(jìn)行的。棋子只能擺在整點(diǎn)上。每個(gè)點(diǎn)不能擺超過(guò)一個(gè)棋子。我們用跳跳棋來(lái)做一個(gè)簡(jiǎn)單的 游戲:棋盤上有3顆棋子,分別在a,b,c這三個(gè)位置。我們要通過(guò)最少的跳動(dòng)把他們的位置移動(dòng)成x,y,z。(棋 子是沒(méi)有區(qū)別的)跳動(dòng)的規(guī)則很簡(jiǎn)單,任意選一顆棋子,對(duì)一顆中軸棋子跳動(dòng)。跳動(dòng)后兩顆棋子距離不變。一次只 允許跳過(guò)1顆棋子。寫一個(gè)程序,首先判斷是否可以完成任務(wù)。如果可以,輸出最少需要的跳動(dòng)次數(shù)。
輸入
第一行包含三個(gè)整數(shù),表示當(dāng)前棋子的位置a b c。(互不相同) 第二行包含三個(gè)整數(shù),表示目標(biāo)位置x y z。(互不相同)輸出
如果無(wú)解,輸出一行NO。如果可以到達(dá),第一行輸出YES,第二行輸出最少步數(shù)。
樣例輸入
1 2 30 3 5
樣例輸出
YES2
【范圍】
100% 絕對(duì)值不超過(guò)10^9
思維神題。 考慮對(duì)于當(dāng)前狀態(tài)的a,b,c有哪些可移動(dòng)方案,設(shè)d1=b-a,d2=c-b,如果d1!=d2,那么b可以向兩邊跳,d1,d2其中小的那個(gè)可以向中間跳;如果d1=d2那么只能由b向兩邊跳。 可移動(dòng)方案最多只有三種,那么可以將每個(gè)狀態(tài)看成一個(gè)點(diǎn),往左右跳看作這個(gè)點(diǎn)的左右子節(jié)點(diǎn),往中間跳看作是這個(gè)點(diǎn)的父節(jié)點(diǎn),如果不能往中間跳,那這個(gè)點(diǎn)就是根節(jié)點(diǎn)。 那么所有狀態(tài)就變成了一個(gè)二叉樹森林,判斷能否完成就變成了判斷兩個(gè)狀態(tài)是否在同一棵樹中,而最小步數(shù)自然就是兩點(diǎn)間的距離了。 但如果將所有狀態(tài)都枚舉出來(lái)顯然不行,例如下面這個(gè)樣例: 1 2 1e9 1e9-1 1e9-2 1e9 要跳1e9級(jí)別這么多次,顯然不能暴力跳。 那么再回到求答案的那一步,兩點(diǎn)間的距離不就是lca分別和兩點(diǎn)深度差的和嗎! 而深度就是每個(gè)點(diǎn)跳到根節(jié)點(diǎn)的步數(shù)。 那么兩點(diǎn)往上跳在原題中就是兩邊的點(diǎn)往中間跳。 因?yàn)樘狞c(diǎn)和被跳的點(diǎn)之間的相對(duì)距離不變,那么就相當(dāng)于將兩個(gè)點(diǎn)都平移了兩點(diǎn)間距離這么多。 假設(shè)d1>d2,那么c最多向左平移(d1-1)/d2次(因?yàn)椴荒芴酵粋€(gè)點(diǎn))。 對(duì)于d1和d2,我們可以像求gcd一樣輾轉(zhuǎn)相除來(lái)求得在二叉樹上給出的這兩點(diǎn)的深度,然后將深度深的點(diǎn)往上跳使兩點(diǎn)深度相同。 接下來(lái)只要找到深度相同的這兩個(gè)點(diǎn)的lca就好了,可以像求倍增lca一樣往上跳驗(yàn)證,也可以用二分答案來(lái)往上跳驗(yàn)證。 我這里用了二分的寫法。注意原題三個(gè)數(shù)不一定按順序給出。 #include<set> #include<map> #include<cmath> #include<stack> #include<queue> #include<vector> #include<bitset> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long using namespace std; ll a,b,c; ll x,y,z; ll dep1,dep2; ll root1,root2; ll l1,l2; ll len; void cmp(ll &a,ll &b,ll &c) {if(a>b){swap(a,b);}if(a>c){swap(a,c);}if(b>c){swap(b,c);} } ll find_root(ll a,ll b,ll c,ll &dep,ll &anc) {ll d1=b-a;ll d2=c-b;while(d1!=d2){if(d1<d2){ll s=d2/d1;ll t=d2%d1;if(t==0){dep+=(s-1);anc=d1;return a+(s-1)*d1;}else{dep+=s;a+=s*d1;d2=t;}}else{ll s=d1/d2;ll t=d1%d2;if(t==0){dep+=(s-1);anc=d2;return a;}else{dep+=s;d1=t;}}}dep=0;anc=d1;return a; } void get_fa(ll &a,ll &b,ll &c,ll dep) {ll d1=b-a;ll d2=c-b;while(dep>0){if(d1<d2){ll s=d2/d1;ll t=d2%d1;if(s>=dep){a+=dep*d1;b+=dep*d1;if(b==c){b=a;a-=d1;}return ;}else{dep-=s;a+=s*d1;b+=s*d1;d2=t;}}else{ll s=d1/d2;ll t=d1%d2;if(s>=dep){c-=dep*d2;b-=dep*d2;if(a==b){b=c;c+=d2;}return ;}else{dep-=s;b-=s*d2;c-=s*d2;d1=t;}}} } int main() {scanf("%lld%lld%lld",&a,&b,&c);scanf("%lld%lld%lld",&x,&y,&z);cmp(a,b,c);cmp(x,y,z);l1=find_root(a,b,c,dep1,root1);l2=find_root(x,y,z,dep2,root2);if(l1!=l2||root1!=root2){printf("NO");return 0;}if(dep1<dep2){len+=dep2-dep1;get_fa(x,y,z,len);}else{len+=dep1-dep2;get_fa(a,b,c,len);}ll l=0;ll r=min(dep1,dep2);ll ans=0;while(l<=r){ll mid=(l+r)/2;ll a1=a,b1=b,c1=c;ll x1=x,y1=y,z1=z;get_fa(a1,b1,c1,mid);get_fa(x1,y1,z1,mid);if(a1==x1&&b1==y1&&c1==z1){ans=mid;r=mid-1;}else{l=mid+1;}}printf("YES\n");printf("%lld",len+ans*2); }
轉(zhuǎn)載于:https://www.cnblogs.com/Khada-Jhin/p/9776977.html
總結(jié)
以上是生活随笔為你收集整理的BZOJ2144跳跳棋——LCA+二分的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: VHDL实现数码管30s倒计时
- 下一篇: 增改