博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P1852 [国家集训队]跳跳棋
阅读量:4677 次
发布时间:2019-06-09

本文共 3415 字,大约阅读时间需要 11 分钟。

P1852 [国家集训队]跳跳棋

 

题目背景

原《奇怪的字符串》请前往 P2543

题目描述

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

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

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

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

输入输出格式

输入格式:

 

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

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

 

输出格式:

 

如果无解,输出一行NO。

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

 

输入输出样例

输入样例#1: 
1 2 30 3 5
输出样例#1: 
YES2

说明

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

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

100% 绝对值不超过10^9 

 

一道神仙题

我们发现一种状态的转移只有三种:

1.中间的往left跳

2.中间的往right跳

3.距离中间近的往里跳

然后我们发现前两种状态都有一种转移方法可以转移回来,这种状态就是第3种状态

于是我们可以将此时的状态为父亲结点,不转移第3种情况,形成一颗二叉树,一个是不会出现重复的状态,另一个是父亲和儿子可以相互转移,儿子的父亲就是儿子进行第3种转移,非常的好

当无法进行第3种转移时,即b-a==c-b,这时就是一棵树里的根,很显然,根不同的两棵树没有任何路径,即无法相互转移

这样问题就变成了找初始状态和终止状态的根,若相同就输出YES,反之就输出NO

这样的时间复杂度依旧是O(N),甚至会更恐怖

观察转移方法:找一个父亲以后是abs(a-b),min(a,b);

我们完全可以一次找到第一个比min(a-b)小的差,即max(a,b)%min(a,b),这样的时间复杂度就变成了和求gcd相同的时间复杂度,即O(logn)

求转移次数,我们可以想到用和LCA极其类似的方法:先将初始状态和终止状态的状态的深度变的相同,再不断向上跳,直到相同即可

细节很多,不一一列举了

上代码(代码丑的一批,除我以外能看明白的都不是一般dalao):

#include
#include
#include
#include
#include
#define rep(i,a,b) for(long long i=a;i<=b;i++)#define dwn(i,a,b) for(long long i=a;i>=b;i--)using namespace std;typedef long long ll;struct zlk{ ll a,b,c,d;}o,p,wyx,h,l1,l2;bool check(){ if(o.a==p.a && p.b==o.b && p.c==o.c) return 1; return 0;}bool check1(){ if(h.a==wyx.a && h.b==wyx.b && h.c==wyx.c) return 1; return 0;}zlk gcd(ll c,zlk t){ if(t.b-t.a==t.c-t.b){ zlk res; res.a=t.a; res.b=t.b; res.c=t.c; res.d=c; return res; } if(t.b-t.a>t.c-t.b){ int cha=(t.c-t.b); t.b=t.a+(t.b-t.a)%(t.c-t.b); if(t.a==t.b) t.b+=cha; t.c=t.b+cha; return gcd(c+1,t); } int cha=(t.b-t.a); t.b=t.c-(t.c-t.b)%(t.b-t.a); if(t.b==t.c) t.b-=cha; t.a=t.b-cha; return gcd(c+1,t);}ll lst,sum;void work(zlk &t){ if(t.b-t.a>t.c-t.b){ int cha=(t.c-t.b); sum+=(t.b-t.a)/(t.c-t.b); lst+=(t.b-t.a)/(t.c-t.b); t.b=t.a+(t.b-t.a)%(t.c-t.b); if(t.a==t.b){ t.b+=cha,--sum; --lst; } t.c=t.b+cha; return; } int cha=(t.b-t.a); sum+=(t.c-t.b)/(t.b-t.a); lst+=(t.c-t.b)/(t.b-t.a); t.b=t.c-(t.c-t.b)%(t.b-t.a); if(t.b==t.c){ t.b-=cha,sum--; --lst; } t.a=t.b-cha;}int main(){ scanf("%lld%lld%lld%lld%lld%lld",&wyx.a,&wyx.b,&wyx.c,&h.a,&h.b,&h.c); if(wyx.a>wyx.c) swap(wyx.a,wyx.c); if(wyx.a>wyx.b) swap(wyx.a,wyx.b); if(wyx.b>wyx.c) swap(wyx.b,wyx.c); o=gcd(0,wyx);wyx.d=o.d; if(h.a>h.c) swap(h.a,h.c); if(h.a>h.b) swap(h.a,h.b); if(h.b>h.c) swap(h.b,h.c); p=gcd(0,h);h.d=p.d; if(!check()){printf("NO"); return 0;} printf("YES\n"); if(h.d
wyx.d){--h.d; work(h);} if(check1()){ printf("%lld",sum); return 0; } while(!check1()){ lst=0; l1=h; l2=wyx; work(h); work(wyx); } sum-=lst; ll ans1=0,ans2=0; if(l1.b-l1.a>l1.c-l1.b && l2.b-l2.a>l2.c-l2.b){ ans1=(l1.b-l1.a)/(l1.c-l1.b); ans2=(l2.b-l2.a)/(l2.c-l2.b); sum+=abs(ans1-ans2); } else if(l1.b-l1.a
l1.c-l1.b){ ans1=(l1.b-l1.a)/(l1.c-l1.b); if((l1.b-l1.a)%(l1.c-l1.b)==0) --ans1; } else{ ans1=(l1.c-l1.b)/(l1.b-l1.a); if((l1.c-l1.b)%(l1.b-l1.a)==0) --ans1; } if(l2.b-l2.a>l2.c-l2.b){ ans2=(l2.b-l2.a)/(l2.c-l2.b); if((l2.b-l2.a)%(l2.c-l2.b)==0) --ans2; } else{ ans2=(l2.c-l2.b)/(l2.b-l2.a); if((l2.c-l2.b)%(l2.b-l2.a)==0) --ans2; } sum+=ans1+ans2; } printf("%lld",sum); return 0;}

  

 

转载于:https://www.cnblogs.com/handsome-zlk/p/10210913.html

你可能感兴趣的文章
BZOJ 1072 排列
查看>>
BZOJ 3779 LCT 线段树 DFS序 坑
查看>>
group by rollup | cube 学习
查看>>
上传图片的步骤
查看>>
hadoop-0.20.2完全分布式集群
查看>>
How to turn off the binary log for mysqld_multi instances?
查看>>
easyui弹出窗关闭前调用确认窗口,先关闭页面后调用弹出窗口
查看>>
BZOJ1018 堵塞的交通(线段树)
查看>>
Python3+Selenium3+webdriver学习笔记8(单选、复选框、弹窗处理)
查看>>
Java String.indexOf() 函数用法小结
查看>>
SSL 1105——【USACO 2.1】顺序的分数(递归+二分)
查看>>
微信 小程序组件 焦点切换
查看>>
github上传文件
查看>>
编译指定安装路径
查看>>
IntelliJ IDEA实时模板变量
查看>>
mysql 多条记录判断相加减进行计算
查看>>
MySQL导入MongoDB
查看>>
JAX-RPC
查看>>
node爬虫
查看>>
Android学习笔记--Menu菜单的使用
查看>>