跳跳棋(信息学奥赛一本通 1559)(洛谷 1852)

【题目描述】

--->我的妈丫,ybt网站的题目粘贴过来修改格式真是太麻烦了,搬运什么的我不干了啦(滑稽

咳咳,那我就简要地讲下这道题的大意吧(当然你也可以略过我的胡言乱语,直接通过时空隧道进入原题吧↓↓↓

时空隧道1->ybt      时空隧道2->luogu)

这道题咧其实本质上就是大家小时候都玩过 应该玩过的跳棋,只不过规则稍稍改变了一丢丢

任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过一颗棋子。

我觉得这句话已经讲得肥肠清楚辽,当然在题目下面还隐藏了另一层含义,也就是说,本题所要求的棋子跳动,只能发生在下面三种情况下:

  1. 中间的棋子往左跳

  2. 中间的棋子往右跳

  3. 左右两颗棋子中距离中间棋子更近的那个棋子往中间跳

可想而知,如若左右两颗棋子(设左边的为a,右边的为c)到中间那颗棋子(设为b)的距离相等,此时已经无法再往中间跳了,那么就只能进行前两种跳动。

事实上,任意一种给定的三颗棋子状态都可以转变成左右两颗棋子到中间棋子距离相等的状态,相当于达到了一种“平衡”,而在这种平衡状态又可以通过向两边跳转变成其他状态,

咦—— 怎么令我不禁想到了二叉树 

说到底这好歹也是道集训队的题目,要是连我这种蒟蒻都能想到那还得了...

即得易见平凡,仿照上例显然。留作习题答案略,读者自证不难。 

反之亦然同理,推论自然成立,略去过程QED,由上可知证毕。

 (我其实是来搞笑的)

设给定的棋子位置为a,b,c(从左到右),要得到的棋子位置为x,y,z(同样是从左往右),那么这道题就是问我们是否可以通过移动棋子使a,b,c变成x,y,z,如果可以就输出最少步数

那么这里为止,我们可以想到,(肥肠关键的一点)将左右两颗棋子到中间棋子距离相等的状态视为树根,那么如果a,b,c状态所在树的树根与x,y,z状态所在树的树根不同,就说明a.b.c状态永远无法到达x,y,z状态,此时就直接输出“NO”,然后结束程序。

反之,就运用“树上倍增法”的思想想让两种状态处在同一层,然后再二分去找LCA,最后输出的答案就是两种状态的层数之差+深度小的那点到最近公共祖先的距离*2。(画图易得)

--->“显然吗?还不显然!”(插入zhd校长名言)

天呐,来自蒟蒻发自内心的感叹,这是什么神题,大佬们都是咋想到LCA的咧

事实上今天心情比较郁闷,不想做题所以扒拉了一堆废话, 啥也不说了直接看代码吧

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 struct node{
  4     int x,y,z;
  5 }b1,b2;
  6 int read()
  7 {
  8     int f=1;char ch;
  9     while((ch=getchar())<'0'||ch>'9')
 10         if(ch=='-')f=-1;
 11     int res=ch-'0';
 12     while((ch=getchar())>='0'&&ch<='9')
 13         res=res*10+ch-'0';
 14     return res*f;
 15 }
 16 void write(int x)
 17 {
 18     if(x<0)
 19     {
 20         putchar('-');
 21         x=-x;
 22     }
 23     if(x>9)write(x/10);
 24     putchar(x%10+'0');
 25 }
 26 void Get(node &b)
 27 {
 28     if(b.x>b.y)swap(b.x,b.y);
 29     if(b.y>b.z)swap(b.y,b.z);
 30     if(b.x>b.z)swap(b.x,b.z);
 31 }
 32 int f1(node &b)
 33 {
 34     int step=0;
 35     Get(b);
 36     while(b.x+b.z!=b.y*2)
 37     {
 38         int d1=b.y-b.x,d2=b.z-b.y;
 39         if(d1<d2)
 40         {
 41             int p=d2/d1;
 42             if(d2%d1==0)p--;
 43             b.x+=d1*p;b.y+=d1*p;
 44             if(b.x>b.y)swap(b.x,b.y);
 45             step+=p;
 46         }
 47         else
 48         {
 49             int p=d1/d2;
 50             if(d1%d2==0)p--;
 51             b.y-=d2*p;b.z-=d2*p;
 52             if(b.y>b.z)swap(b.y,b.z);
 53             step+=p;
 54         }
 55     }
 56     return step;
 57 }
 58 
 59 bool pan(node b1,node b2)
 60 {
 61     if(b1.x==b2.x&&b1.y==b2.y&&b1.z==b2.z)return 1;
 62     else return 0;
 63 }
 64 node f2(node b,int l)
 65 {
 66     Get(b);
 67     while(l)
 68     {
 69         int d1=b.y-b.x,d2=b.z-b.y;
 70         if(d1<d2)
 71         {
 72             int p=d2/d1;
 73             if(d2%d1==0)p--;
 74             if(p>l)p=l;
 75             b.x+=p*d1;b.y+=p*d1;
 76             if(b.x>b.y)swap(b.x,b.y);
 77             l-=p;
 78         }
 79         else
 80         {
 81             int p=d1/d2;
 82             if(d1%d2==0)p--;
 83             if(p>l)p=l;
 84             b.y-=p*d2;b.z-=p*d2;
 85             if(b.y>b.z)swap(b.y,b.z);
 86             l-=p;
 87         }
 88     }
 89     return b;
 90 }
 91 int main()
 92 {
 93     b1.x=read();b1.y=read();b1.z=read();
 94     b2.x=read();b2.y=read();b2.z=read();
 95     Get(b1);Get(b2);
 96     node bb1=b1,bb2=b2;
 97     int t1=f1(bb1),t2=f1(bb2);
 98     if(!pan(bb1,bb2))
 99     {
100         printf("NO");
101         return 0;
102     }
103     int d=abs(t1-t2);
104     if(t1>t2)b1=f2(b1,d);
105     else b2=f2(b2,d);
106     int l=0,r=min(t1,t2),ff=0;
107     while(l<=r)
108     {
109         int m=l+r>>1;
110         bb1=f2(b1,m);
111         bb2=f2(b2,m);
112         if(pan(bb1,bb2))
113         {
114             ff=m;
115             r=m-1;
116         }
117         else l=m+1;
118     }
119     printf("YES\n");
120     write(d+2*ff);
121     return 0;
122 }

猜你喜欢

转载自www.cnblogs.com/ljy-endl/p/11365039.html
今日推荐