@跳跳棋@

  • @跳跳棋@

    • @题目描述@
    • @分析1@
    • @分析2@
    • @代码实现@
    • @END~@

@题目描述@

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

@分析1@

这道题真的很跳……

首先这样的题如果用绝对坐标(a, b, c)来做绝对不好做,所以考虑使用相对距离来表示点。对于三元组(a, b, c)将它表示为(l, r, m) = (b-a, c-b, m),含义为:(左边点离中间点的距离,右边点离中间点的距离,中间点坐标)。

然后对于题目所提到的操作将操作拆为两种:边缘点往中间跳,中间点往两边跳。
当r>l时,左边点可以往中间跳,从(l, r, m)转移到了(l, r-l, m+l)
当l>r时,右边点可以往中间跳,从(l, r, m)转移到了(l-r, r, m-r)
中间点往两边跳没有附加条件,从(l, r, m)可以转移到(l, r+l, m-l)与(l+r, r, m+r)
这样就可以建图,问题转化为求图上两点最短距离。

但是……这还是不够。考虑到中间往两边跳是两边往中间跳的逆操作,我们可以给边定向,即只考虑两边往中间跳的操作。然后我们发现,对于某一个状态(l, r, m),通过两边往中间跳的操作后,l和r不会变得更大,所以这是一个有向无环图。更进一步地,当l < r或l > r时,状态有唯一转移,否则状态无转移。联想到有根树上除根节点外每个节点只有一个父亲,根节点没有父亲。所以这其实是一颗树,且状态(l, r-l, m+l)或(l-r, r, m-r)是状态(l, r, m)的父节点,当 l = r 时状态(l, r, m)是根节点。

问题转化为求树上两点最短距离。
再简单转化,就是求树上两点的LCA。

@分析2@

分析到这一步已经很不容易,但是还还还不够……
考虑到我们一般做LCA的方法:倍增法。先 O(log2n) O ( l o g 2 n ) O(log_2n)的时间将两个点跳到相同深度,再一级一级地同时往上跳直到两个点相同。但是倍增法我们需要 O(n) O ( n ) O(n)的dfs预处理,所以此处并不适用。

再观察一下这个转移的定义:

当r>l时,左边点可以往中间跳,从(l, r, m)转移到了(l, r-l, m+l)
当l>r时,右边点可以往中间跳,从(l, r, m)转移到了(l-r, r, m-r)

再联想一下gcd的减法形式gcd(x, y) = gcd(y, x-y) = gcd(x-y, y) ( x > y )

是不是有点像?对于某一个状态,假设 l < r,则(l, r-l, m+l),(l, r-2l, m+2l),…,(l, r%l, m+r/l*l)都是状态(l, r, m)的祖先。但是!与gcd算法不同的是,如果r%l=0的话则不能跳到最上面的节点,因为在最后的时候 l 将会等于 r。

因为gcd的复杂度可以证明得到不超过 log(n) l o g ( n ) log(n),所以我们就有了一个代替倍增的玩意儿。
具体来说,我们先求出两个点的深度,以及两个点所在树的根节点。比较根节点判断是否有解。
【为了简称,我们称(l, r, m)到达(l, r%l, m+r/l*l)为“大步跳”】【作者太Lazy了233】
然后,对于深度较大的节点,假如它通过“大步跳”到达的节点深度比另外一个节点大,则它就直接跳到深度相同的地方;否则就跳到“大步跳”到达的节点,并继续迭代。
再然后,取两个点“大步跳”到达的点中深度较大的点,假如说在这个点之前它们就已经相遇了,就直接跳到相遇的点作为它们两个点的LCA;否则就同时往上跳到深度较大的点的深度,并继续迭代。

@代码实现@

非常丑陋……不建议参考。
如果还有什么不懂的地方就评论在下面吧,作者会尽力解疑的。
【这道题太毒瘤啦……建图卡死人,LCA卡死人,竟然冒出来个gcd……】

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll min(ll a, ll b) {return a < b ? a : b;
}
ll rootl, rootr, rootm;
ll dep(ll l, ll r, ll m) {if( l == 0 || r == 0 ) {rootl = l, rootr = r, rootm = m;if( l == 0 ) rootl = r, rootm += r;if( r == 0 ) rootr = l, rootm -= l;return 0;}if( r > l )return dep(l, r%l, m+r/l*l) + r/l;else return dep(l%r, r, m-l/r*r) + l/r;
}
void sort(ll &a, ll &b, ll &c) {if( a > b ) swap(a, b);if( b > c ) swap(b, c);if( a > b ) swap(a, b);
}
int main() {ll a, b, c, x, y, z;scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &x, &y, &z);sort(a, b, c), sort(x, y, z);ll l1 = b-a, r1 = c-b, m1 = b;ll l2 = y-x, r2 = z-y, m2 = y;ll d1 = dep(l1, r1, m1);ll rl = rootl, rr = rootr, rm = rootm;ll d2 = dep(l2, r2, m2);if( rootl != rl || rootr != rr || rootm != rm ) {puts("NO");return 0;}else puts("YES");ll ans = 0;while( d1 != d2 ) {if( d1 > d2 ) {if( r1 > l1 ) {ll k = min(r1/l1, d1-d2);d1 -= k, ans += k;l1 = l1, m1 = m1 + k*l1, r1 = r1 - k*l1;}else {ll k = min(l1/r1, d1-d2);d1 -= k, ans += k;r1 = r1, m1 = m1 - k*r1, l1 = l1 - k*r1;}}else {if( r2 > l2 ) {ll k = min(r2/l2, d2-d1);d2 -= k, ans += k;l2 = l2, m2 = m2 + k*l2, r2 = r2 - k*l2;}else {ll k = min(l2/r2, d2-d1);d2 -= k, ans += k;r2 = r2, m2 = m2 - k*r2, l2 = l2 - k*r2;}}}while( l1 != l2 || r1 != r2 || m1 != m2 ) {ll k;if( r1 > l1 ) {if( r2 > l2 ) {if( r1/l1 > r2/l2 )k = r2/l2;else k = r1/l1;d1 -= k, d2 -= k, ans += 2*k;l1 = l1, m1 = m1 + k*l1, r1 = r1 - k*l1;l2 = l2, m2 = m2 + k*l2, r2 = r2 - k*l2;}else {if( r1/l1 > l2/r2 ) {if( l2 % r2 == 0 )k = (m2-m1)/(r2+l1);else k = l2/r2;
/*
如果两个点能跳到同一节点,则:l1=l2-k*r2,r2=r1-k*l1,m1+k*l1=m2-k*r2
解方程可得k,下面同理
*/}else {if( r1 % l1 == 0 )k = (m2-m1)/(r2+l1);else k = r1/l1;}d1 -= k, d2 -= k, ans += 2*k;l1 = l1, m1 = m1 + k*l1, r1 = r1 - k*l1;r2 = r2, m2 = m2 - k*r2, l2 = l2 - k*r2;}}else {if( r2 > l2 ) {if( l1/r1 > r2/l2 ) {if( r2 % l2 == 0 ) k = (m1-m2)/(r1+l2);else k = r2/l2;}else {if( l1 % r1 == 0 )k = (m1-m2)/(r1+l2);else k = l1/r1;}d1 -= k, d2 -= k, ans += 2*k;r1 = r1, m1 = m1 - k*r1, l1 = l1 - k*r1;l2 = l2, m2 = m2 + k*l2, r2 = r2 - k*l2;}else {if( l1/r1 > l2/r2 )k = l2/r2;else k = l1/r1;d1 -= k, d2 -= k, ans += 2*k;r1 = r1, m1 = m1 - k*r1, l1 = l1 - k*r1;r2 = r2, m2 = m2 - k*r2, l2 = l2 - k*r2;}}}printf("%lld\n", ans);
}

@END~@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~

【BZOJ - 2144】跳跳棋相关推荐

  1. BZOJ 2144 跳跳棋

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

  2. BZOJ 2144 跳跳棋(神仙建模题,倍增 LCA,二分)【BZOJ修复工程】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://hydro.ac/d/bzoj/p/2144 是 hydro 的 BZOJ ...

  3. BZOJ 2144 跳跳棋(LCA+欧几里德+二分答案)

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

  4. [bzoj2144]: 跳跳棋

    2144: 跳跳棋 Time Limit: 10 Sec  Memory Limit: 259 MB Submit: 689  Solved: 326 [Submit][Status][Discuss ...

  5. bzoj-2144 跳跳棋

    2144: 跳跳棋 题目链接 时间限制: 10 Sec 内存限制: 259 MB 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一 个简单的游戏: ...

  6. 跳跳棋(国家集训队,LCA,洛谷P1852,BZOJ[2144])

    文章目录 题目 思路 代码 题目 题目链接 描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子.我们用跳跳棋来做一个简单的游戏:棋盘上有333颗棋子,分别在a,b,ca,b ...

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

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

  8. [数论系列一]C Looooops,跳跳棋,The Luckiest number,CF906D Power Tower,Minimal Power of Prime,仪仗队,LCMSUM

    文章目录 C Looooops description solution code 跳跳棋 description solution code The Luckiest number descript ...

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

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

最新文章

  1. 车道线检测算法经典编程
  2. Python 在腾讯研发排第 5,鹅厂 2019 年新增 12.9 亿行代码
  3. Scala中集合类型与java中集合类型转换
  4. 卧槽!12个杭州阿里高学历女员工被初中男骗财骗色1900多万!骗子冒充有钱佬!开豪车保时捷勾搭妹子,法院判无期徒刑!...
  5. jQuery 实现上下,左右滑动
  6. 分布式是写出来的(三)
  7. c语言报错spawning 插1,C语言错误····error spawning c1.exe
  8. 夺冠没含金量!用python和BI可视化分析,湖人赢在这点上
  9. PHP函数的引用传递(地址传递)
  10. .NET——NPOI操作excel
  11. 在docker上和ubuntu上运行InfoGAN
  12. linux [CTRL]+c与[CTRL]+d
  13. git 镜像下载和基本使用
  14. 2021新版OPEN易支付免费开源版 亲测可用
  15. 高通骁龙芯片的随身wifi入门刷机教程
  16. 红皮书 Object
  17. 产品经理(20) #PRD产品需求文档
  18. Qlik Sense 的一些问题【已解决】
  19. Simulink—PMSM电机模块介绍
  20. 老王,快给你的 Spring Boot 做个埋点监控吧!

热门文章

  1. 蓝桥杯国信长天单片机--独立按键和矩阵键盘模块(七)
  2. 关系型数据库非关系型数据库概述
  3. 数字问题---位数上的数字
  4. 你见过卫星眼里的地球吗?带你实时获取地球卫星图并设为桌面背景!真的很美!
  5. 【JavaScript】第一章 简介
  6. Java基础-->一篇讲全Java常用类(详细易懂,建议收藏)
  7. 计算机内存存取时间和存储周期,在计算机中什么是内存存取时间和存储周期?...
  8. 元器件界的“京东”,站在中国智造的风口飞起来
  9. TouchEn nxKey:键盘记录反键盘记录解决方案
  10. 亚马逊自营店铺被跟卖,我们该如何保护我方的listing?