1. 程式人生 > >跳跳棋(9018_1563)(BZOJ_2144)

跳跳棋(9018_1563)(BZOJ_2144)

main ffffff nsa fine fff min clas for 任務

題目:

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

某一天,黃金大神和cjy用跳跳棋來做一個簡單的遊戲:棋盤上有3顆棋子,分別在a,b,c這三個位置。他們要通過最少的跳動把它們的位置移動成x,y,z。(棋子是沒有區別的)

跳動的規則很簡單,任意選一顆棋子,對一顆中軸棋子跳動。跳動後兩顆棋子距離不變。一次只允許跳過1顆棋子。

寫一個程序,首先判斷是否可以完成任務。如果可以,輸出最少需要的跳動次數。

  這道題的狀態是可以在樹上處理的,對於一個中間到兩端距離不等的點,我們把中間的點向左跳作為它的左子樹,向右跳作為右子樹,同理,一個節點的父親就是距中間點較近的點向另一邊跳,顯然,當且僅當兩狀態所屬的節點有公共祖先時題目有解,輸出步數只需要跑lca將目標節點和初始節點到根的距離減去最近公共祖先到根的距離的兩倍即可。實現中註意用gcd來處理向上追溯的過程。

#include <cstdio>
#include <cstring>
#define swap(a,b) swaps=a,a=b,b=swaps;
#define lcas(a,b,c,g) gcdlca(b-a>c-b?b-a:c-b,b-a<=c-b?b-a:c-b,b-a>c-b?-1:1,g,a,b,c); 
#define min(a,b) a<b?a:b
using namespace std;
int ansabc=0,ansxyz=0,ans=0;
int aa,bb,cc,xx,yy,zz,swaps;
bool gcdlca(int
q,int p,short int k,int g,int &x,int &y,int &z){ int r=q%p; int l=q/p; if(r==0){ l--; r=p; if(k==1){ if(l>=g){ y=z-r-p*(l-g); x=z-r-p*(l-g+1); return true; } y=z-r; x
=y-p; ansabc+=l; return false; } else{ if(l>=g){ y=x+r+p*(l-g); z=x+r+p*(l-g+1); return true; } y=x+r; z=y+p; ansabc+=l; return false; } } if(k==1){ if(l>g){ y=z-r-p*(l-g); x=z-r-p*(l-g+1); return true; } y=z-r; x=y-p; ansabc+=l; gcdlca(p,r,-1,g-l,x,y,z); } else{ if(l>g){ y=x+r+p*(l-g); z=x+r+p*(l-g+1); return true; } y=x+r; z=y+p; ansabc+=l; gcdlca(p,r,1,g-l,x,y,z); } } int lca() { int a2,b2,c2,x2,y2,z2,a3=aa,b3=bb,c3=cc; int a1=a2=aa,b1=b2=bb,c1=c2=cc,x1=x2=xx,y1=y2=yy,z1=z2=zz; lcas(x1,y1,z1,0x7fffffff); ansxyz=ansabc; ansabc=0; lcas(a1,b1,c1,0x7fffffff); if(!(a1==x1&&b1==y1&&c1==z1)){ printf("NO\n"); return -1; } // printf("%d\n",ansabc); // printf("%d\n",ansxyz); int t; if((ansabc-ansxyz)>0) t=ansabc-ansxyz; else t=ansxyz-ansabc; ans=ansabc+ansxyz; int ll=min(ansabc,ansxyz); for(int i=0; i<=30; i++) if((1<<i)&t){ if(ansxyz>ansabc){ lcas(x2,y2,z2,1<<i); } else lcas(a2,b2,c2,1<<i); } a3=a2;b3=b2;c3=c2; for(int i=30; i>=0; i--) { if(!(a2==x2&&b2==y2&&c2==z2)&&ll>=(1<<i)) { //printf("%d\n",i); aa=a2,bb=b2,cc=c2; xx=x2;yy=y2;zz=z2; lcas(x2,y2,z2,1<<i); lcas(a2,b2,c2,1<<i); if(a2==x2&&b2==y2&&c2==z2){ a3=a2;b3=b2;c3=c2; a2=aa,b2=bb,c2=cc; x2=xx;y2=yy;z2=zz; continue; } ll-=(1<<i); } } ansabc=0; //printf("%d\n%d\n%d\n",a3,b3,c3); lcas(a3,b3,c3,0x7fffffff); return ans-2*ansabc; } void sso(int &a,int &b,int &c){ if(a>b) swap(a,b); if(b>c) swap(b,c); if(a>b) swap(a,b); return ; } int main() { scanf("%d%d%d%d%d%d",&aa,&bb,&cc,&xx,&yy,&zz); sso(aa,bb,cc); sso(xx,yy,zz); //printf("%d%d%d%d",a,b,c,ansabc); //printf("%d%d%d%d",x,y,z,ansxyz); int yyyy=lca(); if(yyyy==-1) return 0; else printf("YES\n%d",yyyy); return 0; }

跳跳棋(9018_1563)(BZOJ_2144)