BZOJ2144: 跳跳棋

Posted Blue233333

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 
View Code

 

以上是关于BZOJ2144: 跳跳棋的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2144 跳跳棋

bzoj 2144: 跳跳棋——倍增/二分

跳跳棋bzoj2144国家集训队

跳跳棋(9018_1563)(BZOJ_2144)

BZOJ2144: 跳跳棋

BZOJ 2144 跳跳棋(神仙建模题,倍增 LCA,二分)BZOJ修复工程