【题解】P1852 跳跳棋
题意
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。棋盘上有3颗棋子,分别在 \(a,b,c\) 这三个位置。我们要通过最少的跳动把他们的位置移动成 \(x,y,z\) 。(棋子是没有区别的)
跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。
判断是否可以完成任务。如果可以,输出最少需要的跳动次数。
思路
神仙题……非常巧妙地建模。只能说:女少口阿
首先,对于中轴棋子为 \(b\) (中间那个)的情况,显然一直往中间跳可以一直减小范围,直到不能跳为止。这时候就得到了一个非常有用的“Basic” 状态,也就是“根状态”(这怎么跟某道字符串手玩题这么像啊)
然后把 \(b\) 往左右跳的情况看成左右节点状态,那么所有状态构成了一棵二叉树。对于棋盘上所有的 \(a,b,c\) ,状态构成了一个森林。
那么,如果 \((a,b,c)\to (x,y,z)\) ,首要条件是在同一棵树上。这样第一问就解决了。
考虑状态怎么去树根。利用 LCA 的思想,把两个状态到根的距离调整到一样,然后二分向上的步数,最后找到一个 \(L\) 使得两个状态向上 \(L\) 步相遇,那么总答案就是 高度差加上二分答案的两倍。
代码
#include <bits/stdc++.h>
using namespace std;
const int inf=1e9+7;
int sx,sy,sz,dep,mx;
void init( int &x,int &y,int &z )
{
x+=inf; y+=inf; z+=inf;
if ( y>z ) swap( y,z );
if ( x>y ) swap( x,y );
if ( y>z ) swap( y,z );
}
void dfs( int x,int y,int z,int step )
{
int del1=y-x,del2=z-y;
if ( step==mx || del1==del2 ) { sx=x,sy=y,sz=z; dep=step; return; }
if ( del1>del2 )
{
swap( del1,del2 ); int del=del2/del1;
if ( del2%del1==0 ) del--;
if ( step+del<=mx ) dfs( x,y-del*del1,z-del*del1,step+del );
else dfs( x,y-(mx-step)*del1,z-(mx-step)*del1,mx );
}
else
{
int del=del2/del1; del-=(del2%del1==0);
if ( step+del<=mx ) dfs( x+del*del1,y+del*del1,z,step+del );
else dfs( x+(mx-step)*del1,y+(mx-step)*del1,z,mx );
}
}
int main()
{
int x,y,z,a,b,c;
scanf( "%d%d%d",&a,&b,&c ); init( a,b,c );
scanf( "%d%d%d",&x,&y,&z ); init( x,y,z );
mx=inf;
dfs( a,b,c,0 ); int sa=sx,sb=sy,sc=sz,sd=dep;
dfs( x,y,z,0 );
if ( sx!=sa || sy!=sb || sz!=sc ) { printf( "NO" ); return 0; }
printf( "YES\n" );
//------------query1-------------------
int ans=0;
if ( sd>dep )
{
ans=sd-dep; mx=sd-dep;
dfs( a,b,c,0 ); a=sx; b=sy; c=sz;
}
if ( sd<dep )
{
ans=dep-sd; mx=dep-sd;
dfs( x,y,z,0 ); x=sx,y=sy,z=sz;
}
int l=0,r=inf;
while ( l<=r )
{
mx=(l+r)>>1;
dfs( a,b,c,0 ); sa=sx,sb=sy,sc=sz;
dfs( x,y,z,0 );
if ( sa!=sx || sb!=sy || sc!=sz ) l=mx+1;
else r=mx-1;
}
printf( "%d",(l<<1)+ans );
}
【题解】P1852 跳跳棋的更多相关文章
- P1852 跳跳棋 [LCA思想+二分答案]
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有\(3\)颗棋子,分别在\(a,b,c\)这三个位置.我们要通过最少的跳动 ...
- [luogu]P1852跳跳棋
题目重点是每次不能跳过两个棋子 即对于每一个棋子的状态(a,b,c) (a<b<c) 最多有两种移动的方式 1.中间往两边跳 (a,b,c)-->(2b-a,a,c)或(a,c,2b ...
- P1852 [国家集训队]跳跳棋
P1852 [国家集训队]跳跳棋 lca+二分 详细解析见题解 对于每组跳棋,我们可以用一个三元组(x,y,z)表示 我们发现,这个三元组的转移具有唯一性,收束性 也就是说,把每个三元组当成点,以转移 ...
- 洛谷 P1852 [国家集训队]跳跳棋 解题报告
P1852 [国家集训队]跳跳棋 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\), ...
- 洛谷 P1852 [国家集训队] 跳跳棋
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
- [BZOJ 2144]跳跳棋
Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他 ...
- 【洛谷】1852:[国家集训队]跳跳棋【LCA】【倍增?】
P1852 [国家集训队]跳跳棋 题目背景 原<奇怪的字符串>请前往 P2543 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个 ...
- 【bzoj2144】跳跳棋
2144: 跳跳棋 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 492 Solved: 244[Submit][Status][Discuss] ...
- bzoj2144 跳跳棋 二分
[bzoj2144]跳跳棋 Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位 ...
随机推荐
- dpdk网卡收包分析
一个网络报文从网卡接收到被应用处理,中间主要需要经历两个阶段: 阶段一:网卡通过其DMA硬件将收到的报文写入到收包队列中(入队)阶段二:应用从收包队列中读取报文(出队)由于目前正在使用vpp/dpdk ...
- 分布式监控系统之Zabbix基础使用
前文我们了解了分布式监控系统zabbix的相关组件的作用和zabbix的部署,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/13997582.html:今天我们 ...
- kali 系列学习07-攻击之密码生成
比较理想的字典是拖库字典,比如CSDN字典,如果要生成字典,可以使用Crunch 和 rtgen 两个工具, 一.密码生成 1.Crunch (1)启动crunch命令.执行命令如下所示. #crun ...
- 【转】Java工程师知识图谱
一.Java工程师知识图谱(思维导图版) 二.Java工程师知识图谱(文字链接版) 专业基石 数据结构 数组 链表 队列 栈 哈希表 堆 树 图 BitMap 算法思想 排序 查找 分支算法 动态规划 ...
- Camtasia中如何自定义视频输出格式
Camtasia Studio是一款功能全面.操作简单的视频录制和编辑软件,它是很多需要进行录屏操作,比如制作教学视频的用户的不错选择.Camtasia 2020还为用户提供了极大的便利的全面的服务, ...
- ubuntu安装imagick扩展
注意:安装该扩展不要求安装ImageMagick从http://pecl.php.net/package/imagick找到imagick的最新的版本 Linux代码 wget http://pecl ...
- golang 自学系列(四)——debug for vscode
golang 自学系列(四)--(调试)VSCode For Debug 这里如何装 vscode 我就不说了 这里如何在 vscode 正常写代码我也不说了 在能正常用 vscode 写 go 语言 ...
- Ubuntu\Linux 下编写及调试C\C++
一.在Ubuntu\Linux 下编写及调试C\C++需要配置基本的环境,即配置gcc编译器.安装vim编译器,具体配置安装步骤我在这里就不多说了. 二.基本环境配置完了我们就可以进入自己的程序编写了 ...
- 重做系统后 恢复oracle 实例
第一次进行操作,按照网上方法,试了一遍,很多细节搞不清楚,但是还是要记录一下. 备份 old数据库 所用到文件有: XXXXXX\product\11.2.0\dbhome_1\database\pw ...
- oracle set oracle_sid=xxxxxx
本地有多个实例,在cmd 输入 set oracle_sid=xxxxx 来指定要连接的实例 sqlplus xxxx/xxxx@1.1.1.1.1/sid 连接数据库