Checkers 【HDU - 3830】【LCA+二分答案+輾轉相除】
題目連結
題意:我們有(x, y, z)與(a, b, c)這三個點,問,每次可以條一顆棋子,使得新跳的棋子到的位置與原先位置的平均數是中間棋子的位置數。例如:(1, 3, 7)可以跳成(3, 5, 7),就是把“1”以“3”為中間的跳板,跳到“5”這個位置上去的。
很好的一道思維LCA的題,這道題,我們可以化成一棵樹來想,關鍵是在於怎麼建立這棵樹,我們可以舉個樣例來看,我們可以發現(3,5,7)的點中“3”、“7”是沒法跳的,我們只能挪動“5”這個節點,只能把“5”向左或者向右跳。那麼我們就可以看成這樣:把(x, y, z)中(y-x)==(z-y)的點
那麼,假如我們去跑O(N)的複雜度顯然是不行的,我們得做出優化,那麼優化的過程得在圖上實現,假如遇到(0, 100 50000)這樣的點,我們應該怎樣去優化?看到(100-0=100)與(50000-100=49900),不難發現,原點可以這樣子移動:(100, 200, 50000)->(200, 300, 50000)->……->(49800, 49900, 50000),那麼,這是怎樣推出來的呢?用到了輾轉相除。為了逼近(y-x)==(z-y)的狀態,我們得去找路去靠近它,那麼對於(0,100,50000),可以看作(y-x==100)與(z-y==49900),為了靠近,就需要x、y都移動到50000的前一個狀態,不就是可以看成是49900/100,但是因為是整除,會發現最後就有y完完全全的靠在了z上面,所以,我們得處理“-1”,與其最後去減,我們不如做(len_max - 1)/len_min
剩下的,就是怎麼求最近的祖先了,為什麼這麼說?我們將他們放到了同一棵樹上去,如果不等,就是不在同一棵樹上,那麼就是“NO”,否則,就是向上找最近公共祖先的處理方式,我們利用之前所求出來的深度(即到根節點的路徑),我們先放至等深度的高度上,然後二分答案從根節點下來的路徑,去查詢這樣的根節點是否滿足,即可。
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 using namespace std; typedef unsigned long long ull; typedef long long ll; struct node { int x, y, z, deep; node(int a=0, int b=0, int c=0, int d=0):x(a), y(b), z(c), deep(d) {} }S, T; bool cmp_same(node e1, node e2) { return e1.x == e2.x && e1.y == e2.y && e1.z == e2.z; } void SORT(node &X) { if(X.x > X.y) swap(X.x, X.y); if(X.x > X.z) swap(X.x, X.z); if(X.y > X.z) swap(X.y, X.z); } node Root_node(node &X) { node ans = X; int leny_x = 0, lenz_y = 0; while((leny_x = ans.y - ans.x) != (lenz_y = ans.z - ans.y)) { int tmp = 0; if(leny_x > lenz_y) { tmp = (leny_x - 1)/lenz_y; ans.y -= tmp * lenz_y; ans.z -= tmp * lenz_y; } else { tmp = (lenz_y - 1)/leny_x; ans.x += tmp * leny_x; ans.y += tmp * leny_x; } ans.deep += tmp; } X.deep = ans.deep; return ans; } void update(node &X, int deth) { int moved = 0; while(moved < deth) { int at_most = deth - moved; int leny_x = X.y - X.x, lenz_y = X.z - X.y; if(leny_x > lenz_y) { int tmp = (leny_x - 1)/lenz_y; tmp = min(tmp, at_most); moved += tmp; X.y -= tmp * lenz_y; X.z -= tmp * lenz_y; } else { int tmp = (lenz_y - 1)/leny_x; tmp = min(tmp, at_most); moved += tmp; X.x += tmp * leny_x; X.y += tmp * leny_x; } } X.deep -= deth; } int solve(int L, int R) { int ans = S.deep, mid = (L + R)>>1, high = 0; node tmp1, tmp2; while(L <= R) { mid = (L + R)>>1; tmp1 = S; tmp2 = T; high = S.deep - mid; update(tmp1, high); update(tmp2, high); if(!cmp_same(tmp1, tmp2)) R = mid - 1; else { L = mid + 1; ans = mid; } } return 2*(S.deep - ans); } int main() { while(scanf("%d%d%d", &S.x, &S.y, &S.z)!=EOF) { scanf("%d%d%d", &T.x, &T.y, &T.z); SORT(S); SORT(T); S.deep = T.deep = 0; node RS = Root_node(S), RT = Root_node(T); if(!cmp_same(RS, RT)) { printf("NO\n"); continue; } printf("YES\n"); int det_h = abs(S.deep - T.deep); //處理到等深度,所需要的花費 if(S.deep > T.deep) update(S, det_h); else if(S.deep < T.deep) update(T, det_h); printf("%d\n", det_h + solve(0, S.deep)); } return 0; }