整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


题目链接

https://hydro.ac/d/bzoj/p/2144

是 hydro 的 BZOJ 修复工程 !(我也去领了一点题慢慢修着玩,这题就是我修的嘿嘿嘿)

题目描述

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

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

输入格式

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

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

输出格式

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

输入样例

1 2 3
0 3 5

输出样例

YES
2

数据规模与约定

对于 100%100\%100% 的数据输入数据中所有元素绝对值不超过 10910^9109。

Solution

首先我们分析题意,由于每次只能跳过一个棋子,并且必须找到中轴对称跳过去,我们对输入的三个棋子按照从左到右的顺序排序后,三个棋子依次为 x,y,zx,y,zx,y,z,跳棋操作实际上只有三种情况:

  • yyy 向左跳过 xxx
  • yyy 向右跳过 zzz
  • x,zx,zx,z 中距 yyy 更近的棋子向中间跳过 yyy

画图发现每个状态实际上是可以相互转化的,也就是说你跳过去再跳回来,所以的位置都是可以相互通过跳棋操作相互到达的,也就是说我们就可以把每个跳棋位置的状态作为一个节点,全部是可以连通的,形成了一个无向连通图!

我们就可以考虑将数轴上抽象的问题转化为图论的问题,要知道解决图论问题我们是有很多可行的算法的。

将原模型转化为图模型之后,我们发现,如果从初始状态开始,两边的棋子疯狂往中间跳,最后会挤到一个位置不能再往中间跳,并且由于每次往中间跳的时候只有距离更小的棋子才能跳,所以实际上跳的过程中所有的状态都是固定的,而我们从这个挤不动的位置出发往外跳,又可以跳到全部的状态,也即该点和所有状态都是连通的,也就相当于是一个树根!从树根出发,我们发现每次我们都可以往两边跳,是同级的,每次往两边跳实际上就可以看做是树根的子结点。每次两个方向,向左跳的就可以看做是根节点的左儿子,向右跳的就可以看做是根节点的右儿子,并且实际上所有跳的操作能到达的位置状态是固定的,也就意味着我们最终发现这个无向连通图实际上是一个二叉树。

将平面数轴模型转化为二叉树模型之后,我们发现题目中所求的是,从一个位置状态,到另一个位置状态,最少需要多少次操作,由于所有状态均在一个二叉树上,每一个位置状态实际上就是一个结点,那么原问题就变成了求两个结点之间的最短距离

那么显然问题就变得非常简单了!

我们看起来只需要倍增 LCA 计算树上两点间最短距离即可 ~

但是有一些小细节,如果初始位置距离终点非常非常远,我们如果一步一步跳的话,可能会跳很多很多次,比如

1 2 3
1 INF - 1 INF

此时我们每次只能跳 111,而终点离我们有 ∞\infin∞ 那么远,显然要T,考虑优化。

我们发现每次只能跳 111,但是我们会一直重复这个动作知道达到终点,我们显然可以直接用总距离除以每次跳跃的距离 O(1)O(1)O(1) 算出需要重复多少次,然后 O(1)O(1)O(1) 跳达。

这样我们跳的过程类似辗转相除,复杂度实际上只有 log⁡K\log KlogK。

最后求 LCA 即可。类似倍增求 LCA 的过程,我们可以先将初始状态与终点状态中低的那个往上跳到同样的高度,此时我们一起将二者往上继续跳,显然当两点越过 LCA 之后,他们都会到达同一个结点,满足单调性,所以我们就可以二分一下二者在同一高度跳到 LCA 时需要的次数即可。

所以大致的流程就是,我们先 log⁡N\log NlogN 将初始状态以及终点状态一起往中间跳,找树根,与此同时记录结点深度,然后将二者调成到同一深度,再二分到 LCA 的距离即可。

Code

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 1e5 + 6, INF = 0x3f3f3f3f;int n, m, s, t;
ll ans;
int x, y, z, X, Y, Z;
struct node
{int cnt, x, y, z;bool operator == (const node &t) const {if(x == t.x && y == t.y && z == t.z)return true;return false;}
}A, B;
int a[10];void run(node &A, int x, int y, int z)
{int cnt = 0;while(true) {int d1 = y - x, d2 = z - y;if(d1 == d2) break;if(d1 > d2) {int num = (d1 - 1) / d2;cnt += num;// 直接交换 y,z,此时跳跃操作就相当于 y, z 同时向左平移 d2 * numz -= d2 * num;y -= d2 * num;}else {int num = (d2 - 1) / d1;cnt += num;x += d1 * num;y += d1 * num;}}A = {cnt, x, y, z};
}void swap(node &a, node &b)
{swap(x, X), swap(y, Y), swap(z, Z);swap(a.x, b.x), swap(a.y, b.y), swap(a.z, b.z), swap(a.cnt, b.cnt);
}inline bool check(int cnt, int x, int y, int z, int X, int Y, int Z)
{int tot = cnt;while(tot) {int d1 = y - x, d2 = z - y;if(d1 == d2) break;if(d1 > d2) {int num = min(tot, (d1 - 1) / d2);tot -= num;z -= d2 * num;y -= d2 * num;}else {int num = min(tot, (d2 - 1) / d1);tot -= num;x += d1 * num;y += d1 * num;}}tot = cnt;while(tot) {int d1 = Y - X, d2 = Z - Y;if(d1 == d2) break;if(d1 > d2) {int num = min(tot, (d1 - 1) / d2);tot -= num;Z -= d2 * num;Y -= d2 * num;}else {int num = min(tot, (d2 - 1) / d1);tot -= num;X += d1 * num;Y += d1 * num;}}if(x == X && y == Y && z == Z) return true;return false;
}int main()
{scanf("%d%d%d", &a[1], &a[2], &a[3]);sort(a + 1, a + 1 + 3);x = a[1], y = a[2], z = a[3];scanf("%d%d%d", &a[1], &a[2], &a[3]);sort(a + 1, a + 1 + 3);X = a[1], Y = a[2], Z = a[3];//计算树根,顺便统计结点深度run(A, x, y, z);run(B, X, Y, Z);//判断是否存在树根//if(!(A == B)) return 0 * puts("NO");if(A.x != B.x || A.y != B.y || A.z != B.z) return 0 * puts("NO");puts("YES");if(A.cnt < B.cnt) swap(A, B);int tot;tot = A.cnt - B.cnt;ans += tot;//低的结点往上跳,使得二者处于同一深度while(tot) {int d1 = y - x, d2 = z - y;if(d1 == d2) break;if(d1 > d2) {int num = min(tot, (d1 - 1) / d2);tot -= num;z -= d2 * num;y -= d2 * num;}else {int num = min(tot, (d2 - 1) / d1);tot -= num;x += d1 * num;y += d1 * num;}}ll l = 0, r = B.cnt;int ans2 = 0;//二分 LCA 距离while(l <= r) {int mid = (l + r + 1) >> 1;if(check(mid, x, y, z, X, Y, Z)) ans2 = mid, r = mid - 1;else l = mid + 1;}cout << ans + 2 * ans2 << endl;return 0;
}

BZOJ 2144 跳跳棋(神仙建模题,倍增 LCA,二分)【BZOJ修复工程】相关推荐

  1. BZOJ 2144 跳跳棋

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

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

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

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

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

  4. BZOJ 4326 NOIP2015 运输计划(树上差分+LCA+二分答案)

    4326: NOIP2015 运输计划 Time Limit: 30 Sec  Memory Limit: 128 MB Submit: 1388  Solved: 860 [Submit][Stat ...

  5. 倍增LCA(bzoj 3732: Network)

    3732: Network Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1836  Solved: 868 [Submit][Status][Di ...

  6. [bzoj2144]: 跳跳棋

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

  7. bzoj-2144 跳跳棋

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

  8. 【BZOJ - 2144】跳跳棋

    @跳跳棋@ @跳跳棋@ @题目描述@ @分析1@ @分析2@ @代码实现@ @END~@ @题目描述@ Description 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子 ...

  9. 【BZOJ】P2144 跳跳棋

    LCA+二分 看了题面,再看标签:二分也就算了,但...LCA?? 没错,就是LCA! 来慢慢分析一波..... 由于一次只允许跳过1颗棋子并且两个棋子不能同时在一个点,我们以(1,2,3)为例((x ...

最新文章

  1. linux下的module_param()解释【转】
  2. 【Android】页面栈
  3. c#金额转换成中文大写金额
  4. IntellIJ IDEA 配置 Maven 以及 修改 默认 Repository
  5. 菜鸟学SSH(十五)——简单模拟Hibernate实现原理
  6. unix环境高级编程基础知识之第二篇(3)
  7. EF Code First学习笔记:数据库创建(转)
  8. tomcat6的项目能直接在tomcat7上用吗_极尽人性化的设计: 能“隐形”的笔记本电脑支架...
  9. 【六】Jmeter:断言
  10. ubuntu系统编译sh出错 默认dash不是bash
  11. 两台设备有三条链路,请问如何添加?
  12. LINUX双击无法启动解决一例
  13. 使用c++ winhttp实现post请求
  14. 圣诞老人python代码_用Python画圣诞老人的N种方法
  15. [Android稳定性] Android Fd Leak问题分析方法
  16. 【JavaScript】 一万字 JavaScript 笔记(详细讲解 + 代码演示 + 图解)
  17. 小饶学编程之JAVA SE第一部分——二分查找法
  18. 时间序列预测新范式——基于迁移学习的AdaRNN方法
  19. 压缩文件zip怎么查看注释呢,市场上一些破软件不好用啊,我有秘诀
  20. chinapay 新版php接口,php最新銀聯支付chinaPay,最新接口地址

热门文章

  1. OpenCV人脸检测与三角剖分绘制
  2. 基于关键帧的RGB-D视觉惯性里程计
  3. 各种Optimizer梯度下降优化算法回顾和总结
  4. 综述 | 图像去噪方法比较
  5. 微软开源: 老旧照片修复的AI算法
  6. iOS 之 UICollectionView
  7. 从电视到网络,vivo营销之变
  8. 帧中继-实验(第三篇)
  9. php开发之登录注册教程,PHP开发登录注册完整代码之注册PHP页面
  10. 【Python自学】六个上手超强的学习工具,你值得有