题目描述

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

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

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

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

输入输出格式

输入格式:

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

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

输出格式:

如果无解,输出一行NO。

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

输入输出样例

输入样例#1: 复制

  1. 1 2 3
  2. 0 3 5
输出样例#1: 复制

  1. YES
  2. 2

说明

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

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

100% 绝对值不超过10^9

分析

这个题目是真的蛇皮,没话讲。

本题是一道LCA加二分的题目,以我的智商是看不出来的。

下面就来说一下我在SAC大佬的帮助下怎么分析的吧。

设最左边的棋子为a,中间棋子为b,最右边的棋子为c。

显而易见只有三种跳跃方式。

1.b往左边跳。

2.b往右边跳。

3.离b近的往里跳(离b远的不可以跳,因为会越过两个棋子)。

当a,c距离和b一样时,就把当前状态设为a,b,c的起始状态,而且a,b,c的起始状态只有一种。

所以判断一下a,b,c起始状态和不和x,y,z的起始状态一不一样就行了。

怎么判断呢?

显然,两个棋子往中间跳才可以回到起始状态。

但是,如果纯模拟的话就又会超时。

比如1,2,100000000。

这样就会进行很多次操作。

此时,设d1=b-a,d2=c-b。

d1小于d2时我们移动a,然后会发现d1没变,d2减小了d1所以我们可以连续走d2/d1次,反之亦然,此时d2小于d1了换个方向走。注意:d2%d1等于0时走d2/d1-1步就到根了。

然后怎么判断要走多少步呢?

枚举显然不行。

那就二分吧。

如果当前二分得到的mid可以使他们状态相同。

缩小上界,否则扩大下界,下面就贴上代码了(自认为写的很清楚)

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. typedef long long ll;
  6. void sot(ll &a,ll &b,ll &c)
  7. {
  8. if(a>b)
  9. swap(a,b);
  10. if(a>c)
  11. swap(a,c);
  12. if(b>c)
  13. swap(b,c);
  14. }
  15. ll min(ll x,ll y)
  16. {
  17. if(x>y)
  18. return y;
  19. return x;
  20. }
  21. ll getfa(ll a,ll b,ll c,ll &dep,ll &d)
  22. {
  23. ll d1=b-a,d2=c-b;
  24. while(d1!=d2)
  25. {
  26. if(d1<d2)
  27. {
  28. ll sum=d2/d1,t=d2%d1;
  29. if(t==)
  30. {
  31. dep+=(sum-);
  32. d=d1;
  33. return a+(sum-)*d1;
  34. }
  35. else
  36. {
  37. dep+=sum;
  38. d2=t;
  39. a+=(sum)*d1;
  40. b+=(sum)*d1;
  41.  
  42. }
  43. }
  44. else
  45. {
  46. ll sum=d1/d2,t=d1%d2;
  47. if(t==)
  48. {
  49. dep+=(sum-);
  50. d=d2;
  51. return a;
  52. }
  53. else
  54. {
  55. dep+=sum;
  56. d1=t;
  57. b-=(sum)*d2;
  58. c-=(sum)*d2;
  59. }
  60. }
  61. }
  62. dep=;
  63. d=d1;
  64. return a;
  65. }
  66. void fa(ll &a,ll &b,ll &c,ll step)
  67. {
  68. ll d1=b-a,d2=c-b;
  69. while(step>)
  70. {
  71. if(d1<d2)
  72. {
  73. ll sum=d2/d1,t=d2%d1;
  74. if(sum>=step)
  75. {
  76. a+=step*d1;
  77. b+=step*d1;
  78. if(b==c) b=a,a-=d1;
  79. return;
  80. }
  81. else
  82. {
  83. step-=sum;
  84. b=c-t;
  85. a=b-d1;
  86. d2=t;
  87. }
  88. }
  89. else
  90. {
  91. ll sum=d1/d2,t=d1%d2;
  92. if(sum>=step)
  93. {
  94. b-=step*d2;
  95. c-=step*d2;
  96. if(a==b) b=c,c+=d2;
  97. return;
  98. }
  99. else
  100. {
  101. step-=sum;
  102. b=a+t;
  103. c=b+d2;
  104. d1=t;
  105. }
  106. }
  107. }
  108. }
  109. int main()
  110. {
  111. ll a,b,c,x,y,z,dep1=,dep2=,len=,k=,kk=;
  112. cin>>a>>b>>c>>x>>y>>z;
  113. sot(a,b,c);
  114. sot(x,y,z);
  115. ll kzj=getfa(a,b,c,dep1,k);
  116. ll pwq=getfa(x,y,z,dep2,kk);
  117. if(k!=kk||kzj!=pwq) {cout<<"NO";return ;}
  118. else
  119. {
  120. if(dep1<dep2)
  121. {
  122. len+=dep2-dep1;
  123. fa(x,y,z,len);
  124. }
  125. else
  126. {
  127. len+=dep1-dep2;
  128. fa(a,b,c,len);
  129. }
  130. }
  131. ll l=,r=min(dep1,dep2),ans=;
  132. while(l<=r)
  133. {
  134. ll mid=(l+r)/;
  135. ll a1=a,b1=b,c1=c,x1=x,y1=y,z1=z;
  136. fa(a1,b1,c1,mid);
  137. fa(x1,y1,z1,mid);
  138. if(a1==x1&&b1==y1&&c1==z1)
  139. r=mid-,ans=mid;
  140. else
  141. l=mid+;
  142. }
  143. cout<<"YES"<<endl;
  144. cout<<ans*+len;
  145. }

[BZOJ2144]国家集训队 跳跳棋的更多相关文章

  1. 洛谷 P1852 [国家集训队]跳跳棋 解题报告

    P1852 [国家集训队]跳跳棋 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\), ...

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

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

  3. 【洛谷】1852:[国家集训队]跳跳棋【LCA】【倍增?】

    P1852 [国家集训队]跳跳棋 题目背景 原<奇怪的字符串>请前往 P2543 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个 ...

  4. 洛谷 P1852 [国家集训队] 跳跳棋

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

  5. Luogu P1852 BZOJ 2144 [国家集训队]跳跳棋

    qwq 这题一看就不会,如果不是gg让做我是坚决不会做的 画图模拟,因为一次只能跳过一个棋子,所以对于一种情况只有三种移动方式: 中间向左跳 中间向右跳 左或右(距中间近的那个)向中间跳 发现,除了跳 ...

  6. luogu P1852 [国家集训队]跳跳棋

    luogu 直接操作是不可能的,考虑发现一些性质.可以发现如果每次跳的棋子都是两边的,那么最多只有一种方案,那么就把这样操作得到的状态记为当前状态的父亲,从一个状态这样做一定会结束.那么如果两个状态只 ...

  7. [BZOJ2144][国家集训队2011]跳跳棋

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

  8. bzoj2144 【国家集训队2011】跳跳棋

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

  9. bzoj2144 跳跳棋 二分

    [bzoj2144]跳跳棋 Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位 ...

随机推荐

  1. LeetCode(78) Subsets

    题目 Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a subset m ...

  2. 未能加载文件或程序集“System.ServiceModel, Version=2.0.5.0, ...”解决方法

    未能加载文件或程序集“System.ServiceModel, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”或它 ...

  3. linux中的grep命令用法

    原文请移驾:http://blog.csdn.net/greytree/article/details/428532 grep -- print lines matching a pattern (将 ...

  4. JSP表达式语言(EL)

    JSP表达式语言(EL)使得访问存储在JavaBean中的数据变得非常简单.JSP  EL既可以用来创建算术表达式也可以用来创建逻辑表达式.在JSP  EL表达式内可以使用整数型.浮点型.字符串.常量 ...

  5. 大数据学习——mapreduce倒排索引

    数据 a.txt hello jerry hello tom b.txt allen tom allen jerry allen hello c.txt hello jerry hello tom 1 ...

  6. 【ITOO 5】启用MSDTC后的各种问题,以及解决方案

    导读:在上篇博客中说到,通过启动微软的msdtc来实现分布式事务处理,随后,问题就来了,现在,一一总结这个过程中的问题. 一.已禁用对分布式事务管理器(MSDTC)的网络访问. 1.1,问题描述 已禁 ...

  7. bzoj 1701 [Usaco2007 Jan]Cow School牛学校

    [Usaco2007 Jan]Cow School牛学校 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 175  Solved: 83[Submit][S ...

  8. MT6755 使用R63350 IC 出现唤醒概率性闪白,并导致ESD FAIL

    现象描述. 手机自动灭屏后按power键或home 键点亮屏幕,概率性上方有白色的一道,还会闪两三下屏.使用的LCM IC是:r63350, (FHD VDO)屏,附件为mtklog看看是什么原因? ...

  9. 【HDOJ6312】Game(博弈)

    题意: 有一个1到n的序列,两个人轮流取数,取走一个数同时会取走它所有的因子,不能取者为输,两个人都按最优策略取数,问先手是否必胜 思路: #include<cstdio> #includ ...

  10. Heredoc和Nowdoc

    就象heredoc结构类似于双引号字符串,Nowdoc结构是类似于单引号字符串的.Nowdoc结构很象heredoc结构,但是 nowdoc不进行解析操作 . 这种结构很适合用在不需要进行转义的PHP ...