题目描述

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。



我们用跳跳棋来做一个简单的游戏:棋盘上有\(3\)颗棋子,分别在\(a,b,c\)这三个位置。我们要通过最少的跳动把他们的位置移动成\(x,y,z\)。(棋子是没有区别的)

跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过\(1\)颗棋子。

写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

输入格式

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

第二行包含三个整数,表示目标位置\(x\ y\ z\)。(互不相同)

输出格式

如果无解,输出一行\(NO\)。

如果可以到达,第一行输出\(YES\),第二行输出最少步数。

输入输出样例

输入

1 2 3

0 3 5

输出

YES

2

说明/提示

\(20\%\) 输入整数的绝对值均不超过\(10\)

\(40\%\) 输入整数的绝对值均不超过\(10000\)

\(100\%\) 绝对值不超过\(10^9\)

分析

搜标签\(LCA\)搜到的这个题,挺侥幸的。

分析一下,一个三元组,由于每次只能越过一个棋子跳,所以在有序的状态下只有三种可能:

\(1\)、从中间向两边跳。 \(2\)、从左向中间跳,条件是左边的距离小于右边。 \(3\)、从右向中间,条件与上边相反。

根据这个我们可以看出来一个性质:棋子位置的状态可以近似看作一个二叉树,而它的根节点就是左右两边距离相等的情况,也就是只能从中间向两边跳,那么这个问题的第一问就很好解决了,因为假如两个三元组跳到所谓的根的状态的时候的位置不一样,那么肯定从一个不能扩展到另一个,这时候只需要让两个三元组表示的坐标一直跳,直到跳不了了,那么就到了根,判断一下根是否相同,不相同就是\(NO\),否则继续向下找需要跳多少步。

第一个问题解决了,接下来解决第二个:

想一下,如果两个状态在同一个二叉树里,而且我们需要求他们之间跳多少步才能相等。!!!!这不就显然了吗,树上距离当然要用\(LCA\)了。可是这个三元组的状态是没法建树的,所以我们只需要用到求\(LCA\)的思想就行了,即:先把两个状态距离根的步数统一(对应到求\(LCA\)里就是把深度调到一样),然后二分向上跳的步数,最后找到一个两个状态都向上跳\(L\)步,那么总的步数就是之前的高度(步数差)加上二分出来的答案的二倍!!成功切掉。

代码



#include<bits/stdc++.h>
using namespace std;
const int maxn = 5;
const int Inf = 1e9+10;
int a[maxn],b[maxn];
struct Node{//结构体存状态
int a[maxn];
};
int ans,jl;
int dep1,dep2;
Node js(int *a,int dep){
int d1 = a[2] - a[1];
int d2 = a[3] - a[2];
Node ans;
for(int i=1;i<=3;++i){//记录状态
ans.a[i] = a[i];
}
if(d1 == d2)return ans;//如果不能继续跳,那么就是根,直接返回
if(d1 < d2){//左边距离中间小于右边,那么就向右边跳
int step = min(dep,(d2-1)/d1);//找到这个状态能跳多少步
dep -= step;//总的步数减去这个状态走的步数
jl += step;//jl记录的是一共走了多少步
ans.a[2] += step * d1;//更新位置
ans.a[1] += step * d1;
}
else{//左边距离中间大于右边,那么就向左边跳,下边都是一样的,就是更新位置需要减,也就是向左更新
int step = min(dep,(d1-1)/d2);
dep -= step;
jl += step;
ans.a[2] -= step * d2;
ans.a[3] -= step * d2;
}
if(dep)return js(ans.a,dep);//如果还能跳就继续跳
else return ans;不能就返回
}
int main(){
for(int i=1;i<4;++i){
scanf("%d",&a[i]);
}
for(int i=1;i<4;++i){
scanf("%d",&b[i]);
}
sort(a+1,a+4);
sort(b+1,b+4);
Node zt1 = js(a,Inf);//找到第一个三元组的根
dep1 = jl;
jl = 0;
Node zt2 = js(b,Inf);//第二个三元组的根
dep2 = jl;
jl = 0;
int flag = 0;
for(int i=1;i<4;++i){
if(zt1.a[i] != zt2.a[i])flag = 1;
}
if(flag){//如果根状态不一样,直接输出NO
puts("NO");
return 0;
}
if(dep1 > dep2){
swap(dep1,dep2);
for(int i=1;i<4;++i){
swap(a[i],b[i]);
}
}
int l = 0, r = dep1;
ans = dep2 - dep1;//记录深度差
zt1 = js(b,ans);//调整到同一深度
for(int i=1;i<4;++i){//记录下来状态
b[i] = zt1.a[i];
}
while(l <= r){//二分答案
int mid = (l+r)>>1;
flag = 0;
zt1 = js(a,mid);
zt2 = js(b,mid);
for(int i=1;i<4;++i){
if(zt1.a[i] != zt2.a[i])flag = 1;
}
if(flag)l = mid+1;
else r = mid-1;
}
puts("YES");
printf("%d\n",ans+2*l);
return 0;
}

P1852 跳跳棋 [LCA思想+二分答案]的更多相关文章

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

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

  2. 【题解】P1852 跳跳棋

    link 题意 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.棋盘上有3颗棋子,分别在 \(a,b,c\) 这三个位置.我们要通过最少的跳动把他们的位置移动成 \(x,y, ...

  3. [NOIP2015提高&洛谷P2678]跳石头 题解(二分答案)

    [NOIP2015提高&洛谷P2678]跳石头 Description 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之 ...

  4. 跳跳棋[LCA+二分查找]-洛谷1852

    传送门 这真是一道神仙题 虽然我猜到了这是一道LCA的题 但是... 第一遍看题,我是怎么也没想到能和树形图扯上关系 并且用上LCA 但其实其实和上一道lightoj上的那道题很类似 只不过那时一道很 ...

  5. [luogu]P1852跳跳棋

    题目重点是每次不能跳过两个棋子 即对于每一个棋子的状态(a,b,c) (a<b<c) 最多有两种移动的方式 1.中间往两边跳 (a,b,c)-->(2b-a,a,c)或(a,c,2b ...

  6. 洛谷 P2678 跳石头【经典二分答案/贪心】

    题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 NN 块岩石(不含起点和终点的岩石).在比赛过程中,选手们将从 ...

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

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

  8. 7月18日刷题记录 二分答案跳石头游戏Getting

    通过数:1 明天就要暑假编程集训啦~莫名开心 今天做出了一道 二分答案题(好艰辛鸭) 1049: B13-二分-跳石头游戏(二分答案) 时间限制: 5 Sec  内存限制: 256 MB提交: 30  ...

  9. cogs 2109. [NOIP 2015] 运输计划 提高组Day2T3 树链剖分求LCA 二分答案 差分

    2109. [NOIP 2015] 运输计划 ★★★☆   输入文件:transport.in   输出文件:transport.out   简单对比时间限制:3 s   内存限制:256 MB [题 ...

随机推荐

  1. PHP开发环境搭建工具有哪些?

    对于php开发小白来说搭建一个php运行环境就是一道坎! 因为要做php开发,搭建一个能够运行php网站的服务器环境是第一步,传统的php环境软件非常复杂,好在很多公司开发了一键搭建php安装环境,一 ...

  2. Java常用的文档地址

    https://docs.oracle.com/en/ https://docs.oracle.com/en/java/javase/13/   specifications--->langua ...

  3. JavaScript基础函数的属性:记忆模式(019)

    函数在Javascript里是有属性的,因为它们是一种特殊对象.事实上,就算是没有明确声明,函数在最初就已经包含了一些固有的属性,比如所有函数都length这个属性,它可以指出函数声明了多少个参数: ...

  4. 《UNIX环境高级编程》(APUE) 笔记第八章 - 进程控制

    8 - 进程控制 Github 地址 1. 进程标识 每个进程都有一个非负整型表示的 唯一进程 ID .进程 ID 是可复用的(延迟复用算法). ID 为 \(0\) 的进程通常是调度进程,常常被称为 ...

  5. Nginx平滑升级详细步骤-113p.cn

    认识平滑升级 有时候我们需要对Nginx版本进行升级以满足运维人员对其功能的需求,例如添加xxx模块,需要xxx功能,而此时Nginx又在跑着业务无法停掉,这时我们就只能平滑升级了. 平滑升级原理 N ...

  6. 如何查看docker run启动参数命令

    通过runlike去查看一个容器的docker run启动参数 安装pip yum install -y python-pip 安装runlike pip install runlike 查看dock ...

  7. Python3笔记006 - 2.3 变量

    第2章 python语言基础 python语法特点 保留字与标识符 变量 数据类型 运算符 输入和输出 2.3 变量 在python中,不需要先声明变量类型,直接赋值即可创建各种类型的变量. 1.定义 ...

  8. RSA遇上中国剩余定理

    1.Introduction 最近读论文刚好用到了这个,之前只是有耳闻,没有仔细研究过,这里就好好捋一下,会逐步完善 不过貌似CRT(中国剩余定理)的实现更容易被攻击 2. RSA: Overview ...

  9. 哎,老了之display-box

    哎,不想吐槽自己了,表示已远远落后,从今天起开始恶补吧,来一个实例 <html> <head> <meta name="generator" cont ...

  10. 传参问题-HttpMessageNotReableException

    很久没写后台代码,用postMan测试后台接口的时候出现了一个问题: 问题如下: 显而易见是参数问题,我的参数如下图: 我调整参数样式为: 但还是存在问题. 最后调整成用双引号,结果对了.之前没有注意 ...