不一样的LCA——luoguP1852跳跳棋
Problem:
题目大意:
在一条数轴上进行跳跳棋游戏。棋子只能摆在整点上。每个点不能摆超过一个棋子。用跳跳棋完成:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。
跳动的规则:任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。如果可以完成输出YES以及所需步数,如果不行输出NO即可。
对,只允许跳过一颗棋子(因为这个想了好久自闭了)
Solution:
看完题目之后第一反应是不是:woc这什么,跟LCA有什么关系??这哪来的树??
那就对了(%dalao)
分类讨论,发现对于每一种合法的状态(也就是没有棋子重合)只有三种情况能走
1.中点(y)向左边跳
2.中点(y)向右边跳
3.左边(或者右边)往中间跳 =>可以证明由于只能跳过一颗棋子,在d1!=d2时只能走一个
这好像有点像二叉树?(将1.2看做子节点,3看做父亲节点)
对于1.2情况,我们可以发现(以下以1为例):
可以知道,d1>d2时左边的棋子不能跳了,我们最多走d2/d1步,此时d2小于d1了换个方向走,当d2%d1等于0时走d2/d1-1步就到根了。
所以根据这个,我们可以求出开始状态与结束状态的祖先,判断他们的祖先是否相等 =>因为祖先相同就可以通过相反操作得到
这个操作模拟一下就好了,我们可以用除来加快跳((一个个跳会超时的)
模拟部分:
- int d1=y-x;
- int d2=z-y;
- if(d1<d2)
- {
- int step=d2/d1;
- if(d2%d1==) step--;
- if(step>dis) step=dis;
- x+=step*d1;
- y+=step*d1;
- if(x>y) swap(x,y);
- dis-=step;
- }
- else
- {
- int step=d1/d2;
- if(d1%d2==) step--;
- if(step>dis) step=dis;
- z-=d2*step;
- y-=d2*step;
- if(z<y) swap(z,y);
- dis-=step;
- }
找到了公共祖先之后就可以二分查找(查找往上跳的步数)
l是0,r是min(结果与公共祖先的距离,起点与公共祖先的距离)
- int l=,r=min(dep1,dep2),step=;
- while(l<=r)
- {
- int mid=l+r>>;
- b1=go(st,mid);
- b2=go(ed,mid);
- if(pd(b1,b2)) step=mid,r=mid-;
- else l=mid+;
- }
以上是我认为的核心内容(看不懂就感性理解一下)
- #include<iostream>
- #include<cstdio>
- using namespace std;
- struct node{
- int x,y,z;
- }st,ed,b1,b2;
- int dep1,dep2;
- inline int read(){
- char ch;
- int sign=;
- while((ch=getchar())<''||ch>'')
- if(ch=='-') sign=-;
- int res=ch-'';
- while((ch=getchar())>=''&&ch<='')
- res=res*+ch-'';
- return res*sign;
- }
- inline void sort(node &x){
- if(x.x>x.y) swap(x.x,x.y);
- if(x.x>x.z) swap(x.x,x.z);
- if(x.y>x.z) swap(x.y,x.z);
- }
- inline int findfather(node &b){
- int res=;
- sort(b);
- while(b.x+b.z!=b.y*){
- int d1=b.y-b.x;
- int d2=b.z-b.y;
- if(d1<d2){
- int step=d2/d1;
- if(d2%d1==) step--;
- b.x+=step*d1;
- b.y+=step*d1;
- if(b.x>b.y) swap(b.x,b.y);
- res+=step;
- }else{
- int step=d1/d2;
- if(d1%d2==) step--;
- b.z-=step*d2;
- b.y-=step*d2;
- if(b.y>b.z) swap(b.y,b.z);
- res+=step;
- }
- }
- return res;
- }
- inline bool pd(node x,node y){
- if(x.x==y.x&&x.y==y.y&&x.z==y.z) return true;
- return false;
- }
- inline int abs(int x){
- return x>=?x:-x;
- }
- inline node go(node b,int dis){
- sort(b);
- while(dis){
- int d1=b.y-b.x;
- int d2=b.z-b.y;
- if(d1<d2){
- int step=d2/d1;
- if(d2%d1==) step--;
- if(step>dis) step=dis;
- b.x+=step*d1;
- b.y+=step*d1;
- if(b.x>b.y) swap(b.x,b.y);
- dis-=step;
- }else{
- int step=d1/d2;
- if(d1%d2==) step--;
- if(step>dis) step=dis;
- b.z-=d2*step;
- b.y-=d2*step;
- if(b.z<b.y) swap(b.z,b.y);
- dis-=step;
- }
- }
- return b;
- }
- int main(){
- st.x=read();st.y=read();st.z=read();
- ed.x=read();ed.y=read();ed.z=read();
- sort(st);sort(ed);
- b1=st;b2=ed;
- dep1=findfather(b1);
- dep2=findfather(b2);
- if(!pd(b1,b2)){
- printf("NO\n");
- return ;
- }else{
- int c=abs(dep1-dep2);
- if(dep1<dep2)
- ed=go(ed,c);
- else if(dep1>dep2)
- st=go(st,c);
- int l=,r=min(dep1,dep2),step=;
- while(l<=r){
- int mid=l+r>>;
- b1=go(st,mid);
- b2=go(ed,mid);
- if(pd(b1,b2)) step=mid,r=mid-;
- else l=mid+;
- }
- printf("YES\n");
- printf("%d",step*+c);
- }
- return ;
- }
complete code
不一样的LCA——luoguP1852跳跳棋的更多相关文章
- 【LCA】bzoj 2144:跳跳棋
2144: 跳跳棋 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 248 Solved: 121[Submit][Status][Discuss] ...
- BZOJ2144跳跳棋——LCA+二分
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的 游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
- 【洛谷】1852:[国家集训队]跳跳棋【LCA】【倍增?】
P1852 [国家集训队]跳跳棋 题目背景 原<奇怪的字符串>请前往 P2543 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个 ...
- 【BZOJ 2144】 2144: 跳跳棋 (倍增LCA)
2144: 跳跳棋 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 642 Solved: 307 Description 跳跳棋是在一条数轴上进行的 ...
- 跳跳棋——二分+建模LCA
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
- P1852 跳跳棋 [LCA思想+二分答案]
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有\(3\)颗棋子,分别在\(a,b,c\)这三个位置.我们要通过最少的跳动 ...
- bzoj2144 【国家集训队2011】跳跳棋
Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他 ...
- 跳跳棋(9018_1563)(BZOJ_2144)
题目: Hzwer的跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 某一天,黄金大神和cjy用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.他们要 ...
- [BZOJ 2144]跳跳棋
Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他 ...
随机推荐
- node+express修改代码会自动重新运行
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/weixin_40822305/artic ...
- 【转载】c# datatable 判断值是否存在
在C#的数据表格DataTable操作过程中,有时候在操作DataTable前需要判断DataTable中的值是否存在,此时首选需要判断DataTable是否为null值,而后在判断DataTable ...
- FPM 1.1正式版 Search & List
前面写的FPM都是自己练习用的.直到自己正式用了一个,才发现一些小问题.feeder class写在一起和分开写有好有坏,这里就不说了. 自己做了个小的查询报表如下: 现在来按SAP官方的做法来重新做 ...
- Java的自动拆装箱与Integer的缓存机制
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10832303.html 一:基本类型与包装类型 我们知道,Java有8大基本数据类型,4整2浮1符1 ...
- CentOS 7 安装配置分布式文件系统 FastDFS 5.0.5
前言 项目中用到文件服务器,有朋友推荐用FastDFS,所以就了解学习了一番,感觉确实颇为强大,在此再次感谢淘宝资深架构师余庆大神开源了如此优秀的轻量级分布式文件系统,本篇文章就记录一下FastDFS ...
- HDU 1372 Knight Moves 题解
Knight Moves Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- 和群友聊HashTable转到树和图的数据结构
AVL树 前中后遍历 树的遍历深度和广度 树是一种特殊的图 人脉关系属于图数据结构: 并查集 最小生成树 union find 正常图的遍历用广度也能做,但是速度低: 并查集可以降到logn 数据小的 ...
- ie和谷歌的兼容性问题
1.表单的归类 ie下的表单元素在设置了disabled禁用属性之后,在ie下点击,仍然会有焦点.谷歌这是正常的没有焦点 解决方法:给表单元素设置增加属性 unselectable='on' 即可.
- python脚本测试websocket接口协议
import websocket url = 'wss://host:port/rt/tr' #websocket连接地址 ws = websocket.create_connection(url) ...
- 第11节-BLE协议HCI层的硬件接口
本篇博客由韦东山视频整理所得 如何控制链路层让其发出广播包.数据包?通过HCI层向它发出命令,也可以通过ATT层.L2CAP层向LL层发出数据. 学习资料: 蓝牙协议core_v5.0.pdf < ...