bzoj2144 跳跳棋

Description

跳跳棋是在一条数轴上进行的。棋子只能摆在整点上。每个点不能摆超过一个棋子。我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置。我们要通过最少的跳动把他们的位置移动成x,y,z。(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动。跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。  写一个程序,首先判断是否可以完成任务。如果可以,输出最少需要的跳动次数。

Input

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

Output

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

Sample Input

1 2 3
0 3 5

Sample Output

YES
2

【范围】
100% 绝对值不超过10^9

不得不说这题真是tm坑爹想法题,好写不好想考场上很难A掉

如果单纯排列搞一搞貌似有6种走法,但是因为棋子跳的时候只能越过一个棋子,所以对于任意一个状态,它最多只有3种走法。

假设三个点已经从小到大排好,显然中间的棋子无论往左跳还是往右跳都只要越过一个棋子。

考虑最左边的棋子,它不可能直接越过中间和右边的棋子。右边同理。

现在问题来了。两边的棋子越过中间的点是否会直接越过两个点呢?

以2、3、7为例:

2跳过3到达4,是不会超过7的。

但是7越过3到达-1,显然超过了2。所以它跳过了两个棋子,这是不合法的。

这样就得到了结论:只有离中间更近的棋子才可以跳进去。那么确实是最多只有3种情况。

为什么是最多呢?因为还有两边与中间的距离一样近的情况,这样左右都跳不了了,只有中间的可以跳出去。比如3、5、7。

很容易发现,从只有两种跳法的所有状态出发,就可以到达任意一种状态。

什么意思呢?这是一棵二叉树。从2、4、6这样的状态出发,只能4往左右走。把拓展的状态作为左右儿子。左边0、2、6,右边2、6、8。在这两个状态中,如果我们从两边往中间走,显然就还原为父亲节点的状态了。这样是没有意义的。于是只好再从中间完两边走,然后又变成二叉树……于是所有的状态就表示成了以形如等差数列三项的状态为根构成的森林。

这样一来,只要知道两个状态所在的树根是不是一样就可以判断是否有解。具体解的大小可以LCA搞定,或者直接二分答案

假设三个数a、b、c,b-a=s1,c-b=s2。不妨设s1<s2。我们的目标就是把a、c往中间移,最终使得s1=s2。

那么显然a往中间跳的次数就是(s1-1)/s2

而且a、b、c是不计顺序的,所以直接a+=s1*(s1-1)/s2 b+=s1*(s1-1)/2 就好了

时间复杂度大概和gcd是同级的,每次logn

(写了这么长啊……为什么换了个博客废话多起来)

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<deque>
  9 #include<set>
 10 #include<map>
 11 #include<ctime>
 12 #define LL long long
 13 #define inf 0x7ffffff
 14 #define pa pair<int,int>
 15 #define pi 3.1415926535897932384626433832795028841971
 16 using namespace std;
 17 struct zt{
 18     int a,b,c,dep;
 19 }st,nd,rotst,rotnd;
 20 inline void setmax(int &a,int &b,int &c)
 21 {
 22     int mx=a;if (mx<b)mx=b;if (mx<c)mx=c;
 23     int mn=a;if (mn>b)mn=b;if (mn>c)mn=c;
 24     b=a+b+c-mx-mn;
 25     a=mn;
 26     c=mx;
 27 }
 28 bool operator !=(const zt &a,const zt &b)
 29 {return a.a!=b.a||a.b!=b.b||a.c!=b.c;}
 30 bool operator ==(const zt &a,const zt &b)
 31 {return a.a==b.a&&a.b==b.b&&a.c==b.c;}
 32 int l,r,ans;
 33 inline LL read()
 34 {
 35     LL x=0,f=1;char ch=getchar();
 36     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
 37     while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 38     return x*f;
 39 }
 40 inline void inpu(zt &a)
 41 {
 42     a.a=read();a.b=read();a.c=read();
 43     setmax(a.a,a.b,a.c);
 44 }
 45 inline void outpu(zt a)
 46 {printf("%d %d %d %d\n",a.a,a.b,a.c,a.dep);}
 47 inline void cal(zt &a)
 48 {
 49     int dea=a.b-a.a;
 50     int deb=a.c-a.b;
 51     if (dea==deb)return;
 52     if (dea<deb)
 53     {
 54         int des=(deb-1)/dea;
 55         a.dep+=des;
 56         a.a+=des*dea;
 57         a.b+=des*dea;
 58         cal(a);
 59     }else
 60     if (dea>deb)
 61     {
 62         int des=(dea-1)/deb;
 63         a.dep+=des;
 64         a.c-=des*deb;
 65         a.b-=des*deb;
 66         cal(a);
 67     }
 68 }
 69 inline zt gok(zt a,int k)
 70 {
 71     int dea=a.b-a.a;
 72     int deb=a.c-a.b;
 73     if (dea==deb||!k)return a;
 74     if (dea<deb)
 75     {
 76         int des=min((deb-1)/dea,k);
 77         k-=des;
 78         a.dep+=des;
 79         a.a+=des*dea;
 80         a.b+=des*dea;
 81         if (k)return gok(a,k);
 82         else return a;
 83     }else
 84     if (dea>deb)
 85     {
 86         int des=min((dea-1)/deb,k);
 87         k-=des;
 88         a.dep+=des;
 89         a.c-=des*deb;
 90         a.b-=des*deb;
 91         if (k)return gok(a,k);
 92         else return a;
 93     }
 94 }
 95 inline bool jud(int k)
 96 {
 97     return gok(st,k)==gok(nd,k);
 98 }
 99 int main()
100 {
101     inpu(st);setmax(st.a,st.b,st.c);rotst=st;
102     inpu(nd);setmax(nd.a,nd.b,nd.c);rotnd=nd;
103     cal(rotst);
104     cal(rotnd);
105     if (rotst!=rotnd)
106     {
107         printf("NO\n");
108         return 0;
109     }
110     if (rotst.dep<rotnd.dep)swap(st,nd);
111     int dess=abs(rotst.dep-rotnd.dep);
112     st=gok(st,dess);
113     l=0;r=min(rotst.dep,rotnd.dep);
114     while (l<=r)
115     {
116         int mid=(l+r)>>1;
117         if (jud(mid)){ans=mid;r=mid-1;}
118         else l=mid+1;
119     }
120     printf("YES\n%d\n",dess+2*ans);
121 }

bzoj2144

时间: 2024-11-10 01:00:32

bzoj2144 跳跳棋的相关文章

bzoj2144 跳跳棋 二分

[bzoj2144]跳跳棋 Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z.(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子.  写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. Input 第一行包含三个整数,表示当前棋子的

跳跳棋bzoj2144国家集训队

题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z.(棋子是没有区别的) 跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子. 写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. 输入输出格式 输入格式: 第一行包含三个整数,表示当前棋子的位置a b c.(互不相同

跳跳棋(9018_1563)(BZOJ_2144)

题目: Hzwer的跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 某一天,黄金大神和cjy用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.他们要通过最少的跳动把它们的位置移动成x,y,z.(棋子是没有区别的) 跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子. 写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. 这道题的状态是可以在树上处理的,对于一个中间到两端距离不

BZOJ 2144 跳跳棋

2144: 跳跳棋 Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z.(棋子是没有区别的)跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子.  写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. Input 第一行包含三个整数,表示当前棋子的位置a

P1852 [国家集训队]跳跳棋

P1852 [国家集训队]跳跳棋 lca 详细解析见题解 对于每组跳棋,我们可以用一个三元组(x,y,z)表示 我们发现,这个三元组的转移具有唯一性,收束性 也就是说,把每个三元组当成点,以转移关系为边,那么可以得到一棵树 显然最短步数==lca 然后我们就可以愉快地跑lca了 但是还要加优化,就是有可能出现2个靠得近的棋子,但与另一个棋子离得远的情况 这时要跳很多次,但是可以加速,详见代码 code: #include<iostream> #include<cstdio> #in

跳跳棋

其实这道题并不是很难,但是确实不太好想啊... 题目大意: 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动成x,y,z.(棋子是没有区别的) 跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子. 写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的跳动次数. 我们仔细的剖析一下题意: 我们从题目

hzwer的跳跳棋

[题目描述]: Hzwer的跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 某一天,黄金大神和cjy用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.他们要通过最少的跳动把它们的位置移动成x,y,z.(棋子是没有区别的) 跳动的规则很简单,任意选一颗棋子,对一颗中轴棋子跳动.跳动后两颗棋子距离不变.一次只允许跳过1颗棋子. o a o x o b o o 例如:a以x为中轴调到b. 写一个程序,首先判断是否可以完成任务.如果可以,输出最少需要的

1770:跳跳棋

[题目描述] 有一天, Alice和Bob在一个n行m列的棋盘上玩一个叫做“跳跳棋”的游戏,每一个格子上有一个数字. 最开始,Alice在第一行的任意一个格子放一个棋子,并在自己的罚分中加上该格子上的数字. 接下来进行若干轮操作,每轮操作有以下两步: ①Bob可以选择两个上下相邻的格子,在它们之间放上一堵墙.Bob每次操作时,可以修建多堵墙,也可以不修建.但是不能让Alice所在的格子与第n 行不连通. ②Alice将自己的棋子向上下左右方向与其相邻的四个移动一步,并在自己的罚分中加上移动到的格

【BZOJ2144】跳跳棋 模拟gcd以及倍增LCA

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43235053"); } 题意:首先一个状态至多有3种跳的方法的~不能隔着格子跳的~ 题解: 既然有三种方法,那么显然有两种是向外跳,一种是收敛着跳(往里) 然后这个就可以类比成父亲状态和子状态, 里兮为父,外则即子.(诶窝里斗的感觉,,这文言文有点喜