BZOJ2144: 跳跳棋
神题一道。
考虑题目性质。首先对于一个状态,只存在四种情况,即最左/右边的点跳到中间,中间的点跳到左/右。而对于一个状态,显然第一种情况的两种分支不能同时存在,那么题目就可以理解为从$(a,b,c)$找到一条最短的路径可以使得其到达$(x,y,z)$,你完全可以把所有状态存下来随便跑个最短路算法,但是显然是无法承受的,而再研究题目可以发现如果根据一个状态的情况连边,所形成的图是一棵树,而且还是个二叉树,那么就可以利用这个性质。那么假设现在一个状态是$(x,y,z)$,设$t1=y-x,t2=z-y$。如果$t1==t2$,那么就代表这个节点是个根节点。为了简化题目,不考虑每个节点的儿子情况,只考虑他的父亲,那么这个题目就可以看作在一棵树里找两个点的LCA。那么如何求一个节点的第$k$个祖先?
根据gcd的一些奇奇怪怪的性质,可以发现如果$t1>t2$,那么不断将最左边的点移到中间,最多可以移$\frac{t1-1}{t2}$,根据这个也很容易算出移动后的状态。
剩下的就很好搞了, 倍增二分什么的都可以,我用的是二分。
//BZOJ 2144 //by Cydiater //2016.10.20 #include <iostream> #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <ctime> #include <cmath> #include <iomanip> #include <cstdlib> using namespace std; #define ll long long #define up(i,j,n) for(int i=j;i<=n;i++) #define down(i,j,n) for(int i=j;i>=n;i--) const int MAXN=1e6+5; const int oo=0x3f3f3f3f; inline int read(){ char ch=getchar();int x=0,f=1; while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int dep1,dep2,ans=0; struct Node{ int x,y,z; void Sort(){if(x>y)swap(x,y);if(x>z)swap(x,z);if(y>z)swap(y,z);} }a,b; bool operator == (Node x,Node y){return x.x==y.x&&x.y==y.y&&x.z==y.z;} namespace solution{ void init(){ a.x=read();a.y=read();a.z=read(); b.x=read();b.y=read();b.z=read(); } int get(Node node){ int x=node.x,y=node.y,z=node.z; int t1=abs(y-x),t2=abs(z-y),Ans=0; while(t1!=t2&&t1*t2!=0){ if(t1<t2)swap(t1,t2); Ans+=(t1-1)/t2; int tmp=t1;t1=t2;t2=tmp%t2; } return Ans; } Node jump(Node t,int dist){ if(get(t)<dist)return (Node){oo,oo,oo}; t.Sort(); while(dist){ if(t.y-t.x>t.z-t.y){ int t1=t.y-t.x,t2=t.z-t.y; if((t1-1)/t2<dist){ dist-=(t1-1)/t2; t.y-=(t1-1)/t2*t2; t.z-=(t1-1)/t2*t2; }else{ t.y-=dist*t2; t.z-=dist*t2; dist=0; } }else{ int t1=t.y-t.x,t2=t.z-t.y; if((t2-1)/t1<dist){ dist-=(t2-1)/t1; t.x+=(t2-1)/t1*t1; t.y+=(t2-1)/t1*t1; }else{ t.x+=dist*t1; t.y+=dist*t1; dist=0; } } } return t; } void slove(){ if(a==b){puts("YES");puts("0");return;} a.Sort();b.Sort(); dep1=get(a);dep2=get(b); if(dep1<dep2){swap(a,b);swap(dep1,dep2);} ans+=dep1-dep2; a=jump(a,dep1-dep2); if(a.x==oo){puts("NO");return;} if(a==b){puts("YES");cout<<ans<<endl;return;} int leftt=1,rightt=1000000000,mid; while(leftt+1<rightt){ mid=(leftt+rightt)>>1; if(jump(a,mid)==jump(b,mid))rightt=mid; else leftt=mid; } if(jump(a,leftt)==jump(b,leftt)&&jump(a,leftt).x!=oo){ puts("YES"); printf("%d\n",ans+(leftt<<1)); } else if(jump(a,rightt)==jump(b,rightt)&&jump(a,rightt).x!=oo){ puts("YES"); printf("%d\n",ans+(rightt<<1)); } else puts("NO"); } } int main(){ //freopen("input.in","r",stdin); using namespace solution; init(); slove(); return 0; }
BZOJ2144: 跳跳棋的更多相关文章
- bzoj2144 跳跳棋 二分
[bzoj2144]跳跳棋 Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位 ...
- BZOJ2144跳跳棋——LCA+二分
题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的 游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...
- bzoj2144: 跳跳棋(二分/倍增)
思维好题! 可以发现如果中间的点要跳到两边有两种情况,两边的点要跳到中间最多只有一种情况. 我们用一个节点表示一种状态,那么两边跳到中间的状态就是当前点的父亲,中间的点跳到两边的状态就是这个点的两个儿 ...
- BZOJ2144 跳跳棋[建模+LCA]
思维题,思路比较神仙. 个人思路过程:个人只想到了只要中间棋子开始向外跳了,以后就不应该向内跳了,这样很蠢.所以应该要么先向内跳一会,要么直接开始中间的向外跳.不知道怎么处理,就卡住了. 20pts: ...
- bzoj2144 【国家集训队2011】跳跳棋
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\)这三个位置. 我们要通 ...
- 【LCA】bzoj 2144:跳跳棋
2144: 跳跳棋 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 248 Solved: 121[Submit][Status][Discuss] ...
随机推荐
- socket-详细分析No buffer space available
关键词:socket,tcp三次握手,tcp四次握手,2MSL最大报文生存时间,LVS,负载均衡 新年上班第一天,突然遇到一个socket连接No buffer space available的问题, ...
- 设置 Unix,Linux环境下的NLS_LANG
设置 NLS_LANG 变量 1) 正确配置 LC_ALL 参数 2) 配置 telnet/ssh/SecureCRT 客户端的字符集 linux中可以用locale命令来查看 NLS_LANG设置, ...
- ELF Format 笔记(十四)—— 段内容
ilocker:关注 Android 安全(新手) QQ: 2597294287 一个段 (segment) 由一个或多个节 (section) 组成,但这对 android linker 是透明的, ...
- redis 查看的版本
linux环境下查看redis的版本: 查看redis的版本有两种方式:1. redis-server --version 和 redis-server -v 得到的结果是:Redis server ...
- Java连接程序数据源
在实际应用中,可能需要根据表名动态地改变数据源,比如在程序数据集中,通过传进的表名参数,到数据库取出对应的表作为数据源.例如,FineReport是通过AbstractTableData抽象类来读取数 ...
- import com.sun.image.codec.jpeg.JPEGCodec不通过 找不到包
import com.sun.image.codec.jpeg.JPEGCodec; 在Eclipse中处理图片,需要引入两个包: import com.sun.image.codec.jpeg. ...
- Tomjson - 一个"短小精悍"的 json 解析库
Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把Java对象(JavaBean)序列化为json格式字符串,将json格式字符 ...
- 有关sql server 2008无法导入数据库mdf文件的处理方法
解决方法1:根据该博客中的引导,加上自己安装版本的细节,可以添加成功 http://www.2cto.com/database/201408/328930.html 解决方法2: 根据<数据库系 ...
- HOLOLENS不适合加天空盒
加了就有点像VR了,但是视野太窄,所以还是去掉天空盒吧
- python yield from用法
Reading data from a generator using yield from def reader(): """A generator that fake ...