bzoj2144 跳跳棋 二分
【bzoj2144】跳跳棋
Description
跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。 
写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。
Input
第一行包含三个整数,表示当前棋子的位置a b c。(互不相同)第二行包含三个整数,表示目标位置x y z。(互不相同)
Output
如果无解,输出一行NO。如果可以到达,第一行输出YES,第二行输出最少步数。
Sample Input
0 3 5
Sample Output
2【范围】20% 输入整数的绝对值均不超过1040% 输入整数的绝对值均不超过10000100% 绝对值不超过10^9
题解
首先广搜有20分
对于一个状态
例如2 3 7
中间可以往两侧跳,即2 3 7->1 2 7 / 2 3 7->2 7 11
两侧仅有一个能往中间跳,即2 3 7->3 4 7
那么所有的状态就能表示为一棵二叉树,第一种情况为其两个儿子,第二种为其父亲
问题转换为给定树上的两个结点,求其距离
直接暴力可以得40分
可以构造这样的数据
1 2 1000000000
99999998 99999999 1000000000
这样左边要一直往中间跳上上亿次
我们发现若记前两个数差t1,后两个数差t2,不妨设t1<t2
则左边最多往中间跳(t2-1)/t1次
然后只能右边往中间跳,是一个辗转相除的过程,即在logK的时间内我们可以用这种方法得到某个结点它向上K次后的结点,或者根节点,同时还可以顺便算下深度
那么只要求始终两个状态的深度d1,d2,将较深的调整到同一深度
然后二分/倍增求与lca的深度差x
ans=2*x+abs(d1-d2)
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstdio> #define inf 2000000007
#define ll long long
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch>''||ch<''){if (ch=='-') f=-;ch=getchar();}
while(ch<=''&&ch>=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return x*f;
} int t1,t2,tmp,ans;
int a[],b[];
struct data
{
int a[];
}; data cal(int *a,int k)//得到a状态向上走k次的状态
{
data ans;
int t1=a[]-a[],t2=a[]-a[];
for(int i=;i<=;i++)ans.a[i]=a[i];
if(t1==t2)return ans;
if(t1<t2)
{
int t=min(k,(t2-)/t1);
k-=t;tmp+=t;//顺便记录深度
ans.a[]+=t*t1;ans.a[]+=t*t1;
}
else
{
int t=min(k,(t1-)/t2);
k-=t;tmp+=t;
ans.a[]-=t*t2;ans.a[]-=t*t2;
}
if(k)return cal(ans.a,k);//辗转相除
else return ans;
}
bool operator!=(data a,data b)
{
for(int i=;i<=;i++)
if(a.a[i]!=b.a[i])return ;
return ;
}
int main()
{
for(int i=;i<=;i++)a[i]=read();
for(int i=;i<=;i++)b[i]=read();
sort(a+,a+),sort(b+,b+);
data t1=cal(a,inf);int d1=tmp;tmp=;
data t2=cal(b,inf);int d2=tmp;tmp=;
//t1,t2分别为a,b的根,d1,d2为深度
if(t1!=t2){puts("NO");return ;}
if(d1>d2)
{
swap(d1,d2);
for(int i=;i<=;i++)
swap(a[i],b[i]);
}
ans=d2-d1;
t1=cal(b,ans);
for(int i=;i<=;i++)
b[i]=t1.a[i];//较深的向上调整 int l=,r=d1;
while(l<=r)//二分
{
int mid=(l+r)>>;
if(cal(a,mid)!=cal(b,mid))l=mid+;
else r=mid-;
}
printf("YES\n%d",ans+*l);
}
bzoj2144 跳跳棋 二分的更多相关文章
- BZOJ2144跳跳棋——LCA+二分
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的 游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
- 跳跳棋——二分+建模LCA
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
- bzoj2144: 跳跳棋(二分/倍增)
思维好题! 可以发现如果中间的点要跳到两边有两种情况,两边的点要跳到中间最多只有一种情况. 我们用一个节点表示一种状态,那么两边跳到中间的状态就是当前点的父亲,中间的点跳到两边的状态就是这个点的两个儿 ...
- BZOJ2144: 跳跳棋
传送门 神题一道. 考虑题目性质.首先对于一个状态,只存在四种情况,即最左/右边的点跳到中间,中间的点跳到左/右.而对于一个状态,显然第一种情况的两种分支不能同时存在,那么题目就可以理解为从$(a,b ...
- BZOJ2144 跳跳棋[建模+LCA]
思维题,思路比较神仙. 个人思路过程:个人只想到了只要中间棋子开始向外跳了,以后就不应该向内跳了,这样很蠢.所以应该要么先向内跳一会,要么直接开始中间的向外跳.不知道怎么处理,就卡住了. 20pts: ...
- bzoj 2144: 跳跳棋——倍增/二分
Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他 ...
- 【bzoj2144】跳跳棋
2144: 跳跳棋 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 492 Solved: 244[Submit][Status][Discuss] ...
- [BZOJ2144]国家集训队 跳跳棋
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
- [BZOJ2144][国家集训队2011]跳跳棋
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上. 每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\),\(c\)这三个位置. 我们要通 ...
随机推荐
- pathForResource获取资源为nil的原因
利用NSbundle获取 资源文件的时候,如果是自己添加的文件,获取的时候纵使返回nil的解决办法.原因是因为该文件没有添加到资源文件中,只要在添加文件的时候选择添加到 Create Folder R ...
- docker安装Tensorflow并使用jupyter notebook
目前网上提供的大多数的方法都是如下: docker pull tensorflow/tensorflow docker run -it -p : tensorflow/tensorflow 但是按照步 ...
- MINST手写数字识别(一)—— 全连接网络
这是一个简单快速入门教程——用Keras搭建神经网络实现手写数字识别,它大部分基于Keras的源代码示例 minst_mlp.py. 1.安装依赖库 首先,你需要安装最近版本的Python,再加上一些 ...
- vue2.0动画
相对于vue1.0来说,vue2.0的动画变化还是挺大的, 在1.0中,直接在元素中加 transition ,后面跟上名字. 而在vue2.0中,需要把设置动画的元素.路由放在<transit ...
- python之常见的坑
li = [1,2,3,4] # [1,3,4] # 索引值是奇数的删除 for i in range(4): if i % 2 == 1: li.pop(i) # 会报错 print(li) 面试题 ...
- Android 使用 adb命令 远程安装apk
Android 使用 adb命令 远程安装apk ./adb devices 列出所有设备 ./adb connect 192.168.1.89 连接到该设备 ./adb logcat 启动logca ...
- TCP头校验和计算算法详解
我就不管是按“位”(bit)取反相加,还是 按“1的补码”相加了,总之就是把需要进行校验的“字串”加(+)起来,把这相加的 结果取反当做“校验和” (Checksum), 比如,相加的结果是0101, ...
- ios 点餐系统
这个程序的主要界面就是一个TabBarController.总共三个标签,第一个是所有的可点的菜,第二个是已点的菜,第三个是可以留言或者查看所有留言. 下面是第一个页面: 右上角的i按钮是添加新菜,每 ...
- jquery 获取tbody下的第二个tr 及多级标签
<div id="testSlider"> <div class="esriTimeSlider ies-Slider" id="t ...
- ES6变量解构赋值的用法
一.数组赋值(从数组中提取值,按照对应位置,对变量赋值) 1. 完全解构(变量与值数目相等) let arr = [1, 2, 3]; let [a,b,c] = arr; console.log(a ...