洛谷 P1852 [國家集訓隊] 跳跳棋
阿新 • • 發佈:2018-06-12
cdn roo 區別 完成 sin include fine urn line
題目描述
跳跳棋是在一條數軸上進行的。棋子只能擺在整點上。每個點不能擺超過一個棋子。
我們用跳跳棋來做一個簡單的遊戲:棋盤上有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
非常有趣的一道題目。
可以發現只有唯一的一種方案向裏跳,並且一直這樣跳最後總會達到一種再也不能向裏跳的狀態。
於是我們就可以把向裏跳看成在樹上向父親走,而最後b-a = c-b 的狀態就是根節點。
首先如果兩個狀態的樹根不一樣,無解;否則就是一個求LCA的問題了,直接倍增即可。
/* 向前跳: a[1] -= a[2] (須滿足 a[1] > a[2]) 向後跳: a[2] -= a[1] , a[0] += a[1] (須滿足 a[1] < a[2]) a[1] == a[2] 就不能跳了 */ #include<bits/stdc++.h> #define ll long long using namespace std; struct node{ int x,y,z; bool operator !=(const node &u)const{ return x!=u.x||y!=u.y||z!=u.z; } }A,B; int a[3],b[3]; unsigned int ans; node getroot(node x){ if(x.y==x.z) return x; if(x.y>x.z) return getroot((node){x.x,(x.y-1)%x.z+1,x.z}); else{ int o=(x.z-1)/x.y; x.x+=o*x.y,x.z-=o*x.y; return getroot(x); } } int getdeep(node x){ if(x.y==x.z) return 0; if(x.y>x.z){ int o=(x.y-1)/x.z; x.y-=o*x.z; return getdeep(x)+o; } else{ int o=(x.z-1)/x.y; x.x+=o*x.y,x.z-=o*x.y; return getdeep(x)+o; } } node getnode(node x,int lef){ if(x.y==x.z) return x; if(x.y>x.z){ int o=(x.y-1)/x.z; if(o>=lef) return (node){x.x,x.y-lef*x.z,x.z}; x.y-=o*x.z; return getnode(x,lef-o); } else{ int o=(x.z-1)/x.y; if(o>=lef) return (node){x.x+lef*x.y,x.y,x.z-lef*x.y}; x.x+=o*x.y,x.z-=o*x.y; return getnode(x,lef-o); } } inline void solve(){ int da=getdeep(A),db=getdeep(B); if(da<db) swap(da,db),swap(A,B); if(da>db) A=getnode(A,da-db); ans=da-db; if(!(A!=B)) return; for(int i=log(db)/log(2)+1;i>=0;i--) if((1<<i)<=db){ node AA=getnode(A,1<<i); node BB=getnode(B,1<<i); if(AA!=BB) A=AA,B=BB,ans+=1<<(i+1); } ans+=2; } int main(){ for(int i=0;i<3;i++) scanf("%d",a+i); for(int i=0;i<3;i++) scanf("%d",b+i); sort(a,a+3),sort(b,b+3); for(int i=2;i;i--) a[i]-=a[i-1],b[i]-=b[i-1]; A=(node){a[0],a[1],a[2]},B=(node){b[0],b[1],b[2]}; if(getroot(A)!=getroot(B)){ puts("NO"); return 0;} solve(); puts("YES"); printf("%u\n",ans); return 0; }
洛谷 P1852 [國家集訓隊] 跳跳棋