传送门

这真是一道神仙题

虽然我猜到了这是一道LCA的题

但是...

第一遍看题,我是怎么也没想到能和树形图扯上关系

并且用上LCA

但其实其实和上一道lightoj上的那道题很类似

只不过那时一道很裸的板子

这个变了个形

但二分+LCA的思想是没有变的

----------------------------------------------------------------------------

为了方便描述,我们把左边的棋子称为a,中间的棋子称为b,右边的为c。

仔细观察跳棋规则,我们会发现当左右两跳棋到中间距离不等时有三种转移方式(因为不能跳过两个棋子)

  1. b往a方向跳
  2. b往c方向跳
  3. a,c离b距离近的往里跳

a,c到b距离相等的时候只有1,2两种转移方式。

这不就是棵二叉树

往中间跳的是父亲,两旁的是儿子。

重点:

首先要明白棋子是相同的,

所以a,b,c保存的是相对位置,

跳一次相当与把两个棋子平移dis,

dis为它们之间的距离。

设d1=b-a,d2=c-b。

d1小于d2时移动a,

然后会发现d1没变,

d2减小了d1所以可以连续走d2/d1次,

反之亦然,

此时d2小于d1了换个方向走。

注意:d2%d1等于0时走d2/d1-1步就到根了。

计算路径:

先把深度大的节点移到深度小的节点(深度在求根的时候可以顺便求出来)

然后二分到LCA的距离,

往上走n步和求根差不多

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
ll dep1,dep2; inline ll read()//快读
{
ll sum = ,p = ;
char ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-')
p = -;
ch = getchar();
}
while(ch >= '' && ch <= '')
{
(sum *= ) += ch - '';
ch = getchar();
}
return sum * p;
} ll getroot(ll a,ll b,ll c,ll &dep,ll &d)
{
ll d1 = b - a,d2 = c - b;
while(d1 != d2)
{
if(d1 < d2)
{
ll po = d2 / d1;
ll op = d2 % d1;
if(!op)
{
dep += po - ;
d = d1;
return a + d1 * (po - );
}
else
{
dep += po;
d2 = op;
a += po * d1;
b += po * d1;
}
}
else
{
ll po = d1 / d2;
ll op = d1 % d2;
if(!op)
{
dep += po - ;
d = d2;
return a ;
}
else
{
dep += po;
d1 = op;
b -= po * d2;
c -= po * d2;
}
}
}
dep = ;
d = d1;
return a;
} void findfa(ll &a,ll &b,ll &c,ll k)
{
ll d1 = b - a,d2 = c - b;
while(k)
{
if(d1 < d2)
{
ll po = d2 / d1;
ll op = d2 % d1;
if(po >= k)
{
a += k * d1;
b += k * d1;
if(b == c)
b = a,a -= d1;
return;
}
k -= po;
b = c - op;
a = b - d1;
d2 = op;
}
else
{
ll po = d1 / d2;
ll op = d1 % d2;
if(po >= k)
{
c -= k * d2;
b -= k * d2;
if(a == b)
b = a,a -= d1;
return;
}
k -= po;
b = a + op;
c = b + d2;
d1 = op;
}
}
} int main()
{
ll a,b,c,x,y,z,p,q,cnt = ;
a = read(),b = read(),c = read();
x = read(),y = read(),z = read();
ll sum1 = a + b + c,min1 = min(a,min(b,c)),max1 = max(a,max(c,b));
ll sum2 = x + y + z,min2 = min(x,min(y,z)),max2 = max(x,max(y,z));
a = min1,b = sum1 - min1 - max1,c = max1;
x = min2,y = sum2 - min2 - max2,z = max2;
//由于输入有可能不是按照从小到大的顺序输入的,所以小小的处理一下(这个不难理解)
ll pp = getroot(a,b,c,dep1,p);
ll qq = getroot(x,y,z,dep2,q);
/*这两步主要是为了判断是不是NO的情况
因为如果可以从a b c转换到x y z,那么她们不断向里缩小能到达的最终状态一定是一样的
(第一个点相同,每两个点的相邻距离也相同)
由于调用的函数在a到b的距离不等于b到c的距离是
会递归下去
那么
它跳出递归时一定是 每两个点的距离是相等的 所以只用上面()里的两个条件俩判断就可以了
*/
if(qq != pp || q != p)
{
printf("NO");
return ;
}
printf("YES\n");
if(dep1 < dep2)
{
cnt += dep2 - dep1;
findfa(x,y,z,cnt);
}
else
if(dep1 > dep2)
{
cnt += dep1 - dep2;
findfa(a,b,c,cnt);
}//让深度更深的点向上跳到和另一个同样的深度
//深度:转化到最小(最压缩状态)所需要的操作次数
ll l = ,r = min(dep1,dep2),ans = ;
while(l <= r)//二分找LCA(找最小的,并且,保证可以转化的操作次数)
{
ll mid = l + r >> ;
ll aa = a,bb = b,cc = c,xx = x,yy = y,zz = z;
findfa(aa,bb,cc,mid);
findfa(xx,yy,zz,mid);
if(aa == xx && bb == yy && cc == zz)//可以转化--可能是答案,也可能比答案大
{
ans = * mid;
r = mid - ;
}
else
l = mid + ;
}
printf("%lld",ans + cnt);
return ;
}

跳跳棋[LCA+二分查找]-洛谷1852的更多相关文章

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

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

  2. P1852 跳跳棋 [LCA思想+二分答案]

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

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

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

  4. 二分答案 & 洛谷 P2678 跳石头

    首先让我们先学一下二分答案这个东西...   二分答案,肯定与二分有关,还与可能是答案的东西有关... 二分答案的准确定义: 二分答案是指在答案具有单调性的前提下,利用二分的思想枚举答案,将求解问题转 ...

  5. bzoj2144: 跳跳棋(二分/倍增)

    思维好题! 可以发现如果中间的点要跳到两边有两种情况,两边的点要跳到中间最多只有一种情况. 我们用一个节点表示一种状态,那么两边跳到中间的状态就是当前点的父亲,中间的点跳到两边的状态就是这个点的两个儿 ...

  6. P1852 [国家集训队]跳跳棋

    P1852 [国家集训队]跳跳棋 lca+二分 详细解析见题解 对于每组跳棋,我们可以用一个三元组(x,y,z)表示 我们发现,这个三元组的转移具有唯一性,收束性 也就是说,把每个三元组当成点,以转移 ...

  7. 【洛谷】1852:[国家集训队]跳跳棋【LCA】【倍增?】

    P1852 [国家集训队]跳跳棋 题目背景 原<奇怪的字符串>请前往 P2543 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个 ...

  8. 洛谷P3345 [ZJOI2015]幻想乡战略游戏(动态点分治,树的重心,二分查找,Tarjan-LCA,树上差分)

    洛谷题目传送门 动态点分治小白,光是因为思路不清晰就耗费了不知道多少时间去gang这题,所以还是来理理思路吧. 一个树\(T\)里面\(\sum\limits_{v\in T} D_vdist(u,v ...

  9. 洛谷P4299 首都(BZOJ3510)(LCT,树的重心,二分查找)

    Update:原来的洛谷U21715已成坑qwq 已经被某位管理员巨佬放进公共题库啦!又可以多一个AC记录啦! 洛谷题目传送门 其实也可以到这里交啦 思路分析 动态维护树的重心 题目中说到国家的首都会 ...

随机推荐

  1. RabbitMQ消息队列(十一)-如何实现高可用

    在前面讲到了RabbitMQ高可用集群的搭建,但是我们知道只是集群的高可用并不能保证应用在使用消息队列时完全没有问题,例如如果应用连接的RabbitMQ集群突然宕机了,虽然这个集群时可以使用的,但是应 ...

  2. 补习系列(4)-springboot 参数校验详解

    目录 目标 一.PathVariable 校验 二.方法参数校验 三.表单对象校验 四.RequestBody 校验 五.自定义校验规则 六.异常拦截器 参考文档 目标 对于几种常见的入参方式,了解如 ...

  3. ES6躬行记(17)——Map

    一.Map Map类似于Object(对象),可用来存储键值对,但需要通过SameValueZero算法保持键的唯一性.与Set一样,在使用之前也得要实例化,如下代码所示,构造函数Map()中的参数也 ...

  4. 一个emoji引发的一条血案:mysql存储emoji表情字符时报错解决

    以下是我插入一条带表情的数据到mysql后出现错误 2019-03-04 14:24:40,462 ERROR 2807 [-/139.199.27.244/-/2ms POST /api/activ ...

  5. Python批量修改寄存器的值

    在写代码过程中,我们修改代码中寄存器的值,但是有时寄存器的数据较多,手动修改容易出现错误而且花费的时间长 这是一段寄存器的配置值: 0x00, 0x34  0x35, 0x25  0x10, 0xd4 ...

  6. redo/declare/typeset

    变量设置功能,都是由命令行直接设置的,那么,可不可以让使用者能够经由键盘输入? 什么意思呢?是否记得某些程序执行的过程当中,会等待使用者输入 "yes/no"之类的讯息啊? 在 b ...

  7. [Go] Go的WaitGroup计数信号量

    WaitGroup是一个计数信号量,可以用来记录并维护运行的goroutine,如果WaitGroup的值大于0,Wait方法就会阻塞 调用Done方法来减少WaitGroup的值,并最终释放main ...

  8. C# 如何隐藏或显示工作表中的网格线

    我们知道Excel中有许多虚线形式的网格线,它们用于区分Excel工作表中的单元格.有了网格线,读者可以轻松地查看和核对工作表中的数据.Excel工作表中,网格线是默认存在的,但我们可以根据自身的需求 ...

  9. Spring笔记04_AOP注解开发_模板_事务

    目录 1. Spring基于AspectJ的注解的AOP开发 1. 1 SpringAOP的注解入门 1.2 Spring的AOP的注解通知类型 1.2.1 @Before:前置通知 1.2.2 @A ...

  10. Axure rp8团队原型图开发

    说道原型图大家都不陌生,Axure rp作为这类工具可以说在网页布局的设计给开发人员提供了很大便利,目前我只熟悉过这一种,不知道小伙伴们有没有其他好用的工具推荐给大家用一下吗.好了,废话不多说,今天给 ...