BZOJ2144: 跳跳棋
求三个人从a,b,c这三个位置跳到x,y,z最少多少步。跳:任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。
从它跳的性质出发,向内跳只有一种操作,而向外跳有两种。这就是说,每个状态可以找到一个唯一前趋,有两个后继。这是一棵二叉树!求两个状态的最短路就是求他们到lca的距离和!
类似于lca,先看两个状态能跳到的最终状态是否相同,在这个过程中记下两个状态的深度。然后让深度大的先跳,跳到两个状态深度一样后,二分答案让两个一起跳。
问题是怎么快速地跳指定步数,记中间那个人和左右的间距为l和r,如果l小,那左边人往里跳一步,就会:l->l,r->r-l,更相减损,最后变成l,r%l,这r/l步可以很快跳。所以把r/l和指定步数x取个min让间隔小的那边的人跳就好了。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 //#include<iostream> 6 using namespace std; 7 8 int a,b,c,x,y,z; 9 int ra,rb,rc,rx,ry,rz; 10 void play(int a,int b,int c,int &ra,int &rb,int &rc,int &dep) 11 { 12 // cout<<a<<' '<<b<<' '<<c<<endl; 13 int l=b-a,r=c-b; 14 if (l==r) {ra=a;rb=b;rc=c;return;} 15 if (l<r) 16 { 17 if (!(r%l)) play(c-l-l,c-l,c,ra,rb,rc,dep),dep+=r/l-1; 18 else play(c-r%l-l,c-r%l,c,ra,rb,rc,dep),dep+=r/l; 19 } 20 else 21 { 22 if (!(l%r)) play(a,a+r,a+r+r,ra,rb,rc,dep),dep+=l/r-1; 23 else play(a,a+l%r,a+l%r+r,ra,rb,rc,dep),dep+=l/r; 24 } 25 } 26 int ccc(int a,int b,int c) 27 { 28 int l=b-a,r=c-b; 29 if (l<r) 30 { 31 if (!(r%l)) return r/l-1; 32 else return r/l; 33 } 34 else 35 { 36 if (!(l%r)) return l/r-1; 37 else return l/r; 38 } 39 } 40 void jump(int &a,int &b,int &c,int x) 41 { 42 if (a==b || b==c) return; 43 int l=b-a,r=c-b; 44 if (l<r) 45 { 46 a+=x*l; 47 b+=x*l; 48 } 49 else 50 { 51 c-=x*r; 52 b-=x*r; 53 } 54 } 55 //LL mul(LL a,LL b) {return a*b-(LL)((double)a/p*b)*p;} 56 void Jump(int &a,int &b,int &c,int x) 57 { 58 for (;x;) 59 { 60 int tmp=min(x,ccc(a,b,c)); 61 jump(a,b,c,tmp); 62 x-=tmp; 63 } 64 } 65 bool check(int num) 66 { 67 int ta=a,tb=b,tc=c,tx=x,ty=y,tz=z; 68 // cout<<ta<<' '<<tb<<' '<<tc<<' '<<tx<<' '<<ty<<' '<<tz<<endl; 69 Jump(ta,tb,tc,num);Jump(tx,ty,tz,num);//cout<<"->\n"; 70 // cout<<ta<<' '<<tb<<' '<<tc<<' '<<tx<<' '<<ty<<' '<<tz<<endl; 71 return ta==tx && tb==ty && tc==tz; 72 } 73 void sos(int &a,int &b,int &c) 74 { 75 if (a>b) {int t=a;a=b;b=t;} 76 if (a>c) {int t=a;a=c;c=t;} 77 if (b>c) {int t=b;b=c;c=t;} 78 } 79 int main() 80 { 81 scanf("%d%d%d%d%d%d",&a,&b,&c,&x,&y,&z); 82 sos(a,b,c);sos(x,y,z); 83 int dep=0,ddd=0; 84 play(a,b,c,ra,rb,rc,dep);play(x,y,z,rx,ry,rz,ddd); 85 // cout<<ra<<' '<<rb<<' '<<rc<<endl; 86 // cout<<rx<<' '<<ry<<' '<<rz<<endl; 87 // cout<<dep<<' '<<ddd<<endl; 88 if (ra!=rx || rb!=ry || rc!=rz) puts("NO"); 89 else 90 { 91 puts("YES"); 92 if (dep<ddd) {swap(a,x);swap(b,y);swap(c,z);swap(dep,ddd);} 93 int ans=0; 94 // cout<<a<<' '<<b<<' '<<c<<' '<<x<<' '<<y<<' '<<z<<endl; 95 while (dep>ddd) {int tmp=min(dep-ddd,ccc(a,b,c));ans+=tmp;jump(a,b,c,tmp);dep-=tmp;} 96 // cout<<a<<' '<<b<<' '<<c<<' '<<x<<' '<<y<<' '<<z<<' '<<ans<<endl;} 97 int L=0,R=ddd; 98 while (L<R) 99 { 100 const int mid=(L+R)>>1; 101 if (check(mid)) R=mid; 102 else L=mid+1; 103 } 104 printf("%d\n",ans+L*2); 105 } 106 return 0; 107 } 108