Description

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。 写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

Input

第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)第二行包含三个整数,表示目标位置x y z。(互不相同)

Output

如果无解,输出一行NO。如果可以到达,第一行输出YES,第二行输出最少步数。

Sample Input

1 2 3
0 3 5

Sample Output

YES
2

HINT

【范围】
100% 绝对值不超过10^9

题解

设初始状态为$sta$,目标状态为$fin$。我们先拿出初始状态三个球讨论。

由于三个球其实是相同的,则他们的相互顺序是不影响的,我们可以先按坐标从左至右排序为$a$,$b$,$c$。

平面上有三个球,我们来讨论它们跳的不同情况。

设:$p=b-a$,$q=c-b$

那么$b$可以跳动到$a$左边,或者$c$右边。

同时,如果$p<q$,那么$a$可以跳到$bc$中间,如果$p>q$,那么$c$可以跳到$ab$中间。

也就是说,如果$p≠q$,那么一个状态有$3$种跳法,但如果$p=q$,那么只有$2$种跳法。

如果我们用图来表示状态之间的关系,就很容易发现,状态之间组成的联系实际上是二叉树组成的森林。

每一个$p=q$的状态都是一棵二叉树的根。

其余的每个状态,$a$或$c$往中间跳表示往父亲节点走一步,对于所有状态,中间节点往左右跳分别对应往左右孩子走一步。

原问题转换成了树上最短路问题。原问题就是:

1.$sta$和$fin$是否同根。

2.如果同根,求$sta$到$fin$的距离。

这两个问题都可以用$LCA$来解决。

如果$sta$和$fin$不存在$LCA$那么输出$NO$。

如果存在,那么计算$LCA(sta,fin)$到$sta$和$fin$分别的距离,相加即为答案。

我们可以通过辗转相除法直接计算$sta$和$fin$在二叉树中的深度。

我们用类似倍增的$LCA$的思想,先将两个节点跳到同一深度,

求$2$个深度相同的点的$LCA$,我们可以采用二分答案的方法。

对于二分答案:$LCA$到$sta$的距离$mid$,如果$sta$往上走$mid$和$fin$往上走$mid$到达的点相同,那么 答案$≤mid$

否则 答案$>mid$

如此一来,我们得到了一个$O(log^2 D)$的算法,$D$为深度。

 #include<set>
#include<map>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define LL long long
#define Max(a,b) ((a)>(b) ? (a):(b))
#define Min(a,b) ((a)<(b) ? (a):(b))
using namespace std; int depth;
struct node
{
int a,b,c;
node (){}
node (int _a,int _b,int _c) {a=_a;b=_b;c=_c;}
void sort()
{
   if (b>c) swap(b,c);
   if (a>b) swap(a,b);
   if (b>c) swap(b,c);
}
bool operator == (const node &B)
const{
   return (a==B.a)&&(b==B.b)&&(c==B.c);
}
node get_root()
{
   int dep=;
   node tmp=node(a,b,c);
   int p=tmp.b-tmp.a,q=tmp.c-tmp.b;
   while (p!=q)
   {
   int r;
   if (p>q) r=(p-)/q,tmp.b-=r*q,tmp.c-=r*q;
  else if (p<q) r=(q-)/p,tmp.a+=r*p,tmp.b+=r*p;
   p=tmp.b-tmp.a,q=tmp.c-tmp.b;
  dep+=r;
   }
  depth=dep;
  return tmp;
}
node jump(int step)
{
  node tmp=node(a,b,c);
   int p=tmp.b-tmp.a,q=tmp.c-tmp.b;
  while (p!=q&&step)
  {
   int r;
  if (p>q)
  {
     r=(p-)/q;
     if (r>step) r=step;
     tmp.b-=r*q,tmp.c-=r*q;
   }
   else if (p<q)
   {
     r=(q-)/p;
     if (r>step) r=step;
    tmp.a+=r*p,tmp.b+=r*p;
  }
  p=tmp.b-tmp.a,q=tmp.c-tmp.b;
  step-=r;
  }
  return tmp;
}
}sta,fin; int main()
{
scanf("%d%d%d",&sta.a,&sta.b,&sta.c);
scanf("%d%d%d",&fin.a,&fin.b,&fin.c);
sta.sort();
fin.sort();
if (sta.get_root()==fin.get_root())
{
   printf("YES\n");
   int dep_sta,dep_fin;
   sta.get_root();dep_sta=depth;
   fin.get_root();dep_fin=depth;
   if (dep_sta<dep_fin) swap(sta,fin),swap(dep_sta,dep_fin);
   int len=dep_sta-dep_fin;
   sta=sta.jump(len);
  dep_sta=dep_fin;
   if (sta==fin) printf("%d\n",len);
   else
   {
   int l=,r=dep_sta,ans=dep_sta;
   while (l<=r)
   {
     int mid=(l+r)>>;
    if (sta.jump(mid)==fin.jump(mid)) ans=mid,r=mid-;
     else l=mid+;
   }
   printf("%d\n",len+*ans);
   }
}
else printf("NO\n");
return ;
}

[BZOJ 2144]跳跳棋的更多相关文章

  1. 【LCA】bzoj 2144:跳跳棋

    2144: 跳跳棋 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 248  Solved: 121[Submit][Status][Discuss] ...

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

    Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他 ...

  3. 【BZOJ 2144】 2144: 跳跳棋 (倍增LCA)

    2144: 跳跳棋 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 642  Solved: 307 Description 跳跳棋是在一条数轴上进行的 ...

  4. 【bzoj2144】跳跳棋

    2144: 跳跳棋 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 492  Solved: 244[Submit][Status][Discuss] ...

  5. BZOJ2144: 跳跳棋

    传送门 神题一道. 考虑题目性质.首先对于一个状态,只存在四种情况,即最左/右边的点跳到中间,中间的点跳到左/右.而对于一个状态,显然第一种情况的两种分支不能同时存在,那么题目就可以理解为从$(a,b ...

  6. bzoj2144 【国家集训队2011】跳跳棋

    Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他 ...

  7. 跳跳棋(9018_1563)(BZOJ_2144)

    题目: Hzwer的跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 某一天,黄金大神和cjy用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.他们要 ...

  8. BZOJ2144跳跳棋——LCA+二分

    题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的 游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...

  9. 洛谷 P1852 [国家集训队]跳跳棋 解题报告

    P1852 [国家集训队]跳跳棋 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\), ...

随机推荐

  1. 听翁恺老师mooc笔记(2)-第一个程序--&运算符

    使用devC++写hello world 第一步:文件-新建-源代码.然后输入"输出hello world"程序: 注意:写程序时关闭中文输入法,否则语句输入的分号可能会被识别为错 ...

  2. Beta 凡事预则立

    写在Beta冲刺前 关于组长是否重选的议题和结论 总体结论 组长无需更换 队内无人替代 理由 当前组长能够较好的号召和组织团队成员进行工作 当前组长能够对项目有合理的规划 当前组长被大家一致认可可以继 ...

  3. C语言作业--数组

    一.PTA实验作业 题目1:7-5 数组循环左移 1. 本题PTA提交列表 2. 设计思路 定义俩个整数 n,m 定义循环变量i,j,x 定义变量k用来存放下标 定义变量number用于交换数值 定义 ...

  4. django模板(一)

    模板(一) 实验简介 在前一章中,你可能已经注意到我们在例子视图中返回文本的方式有点特别. 也就是说,HTML被直接硬编码在 Python 代码之中. def current_datetime(req ...

  5. zookeeper 启动失败 BindException: Address already in use 或者Error contacting service. It is probably not running

    平台:centos-6.3-i386 jdk-7u51 storm 0.9.1 python 2.6.6   hadoop 1.2.1 今天上午装storm的时候遇到这个问题,好郁闷.把网上介绍的方法 ...

  6. css3动画transition详解2

    transition主要包含四个属性值:执行变换的属性:transition-property,变换延续的时间:transition-duration,在延续时间段,变换的速率变化transition ...

  7. 记一次SQL调优/优化(SQL tuning)——性能大幅提升千倍以上

    好久不写东西了,一直忙于各种杂事儿,恰巧昨天有个用户研发问到我一个SQL调优的问题,说性能太差,希望我能给调优下,最近有些懒,可能和最近太忙有关系,本来打算问问现在的情况,如果差不多就不调了,那哥们儿 ...

  8. JAVA_SE基础——70.Math类

    package cn.itcast.other; /*  Math 数学类, 主要是提供了很多的数学公式.    abs(double a)  获取绝对值  ceil(double a)  向上取整 ...

  9. JAVA_SE基础——20.数组的常见操作

    1.遍历数组 使用for循环来遍历数组 代码如下: public class Ergodic { public static void main(String[] args) { int[] arr ...

  10. MongoDb进阶实践之五 MongoDB修改命令详述

    一.引言         上一篇文章我们已经详细介绍了MongoDB数据库的有关查询的内容,但是这只是所有查询命令的冰山一角.所有查询命令都写完也没有必要,我只是写了一些常用的命令,对MongoDB的 ...