Description

Link.

在一个数轴上给你三个点,移动方法是彼此为中点进行跳跃,不能同时越过两颗棋子。

给出初始状态和目标状态,问能否从初始状态跳到目标状态。若能,输出最少步数。

棋子之间互相没有差别。

Solution

这道题是我们去年学倍增的时候LF给我们放的一道题(实际上和倍增没有半毛钱的关系。

啊对我就是一道题从去年做到今年(我不管做出来了就是我的题量XD/xyx

不扯了说正事儿。

其实拿到这道题我是很懵的,完全不知道该怎么入手。

然后我们拿出传统手艺手玩数据。我们可以发现对于一个三元组 \((x,y,z)\) 只有三种移动的方案:

(啊对了,说一下这里的三元组表示的是一种位置关系,即 \(x\) 在左 \(y\) 在中间 \(z\) 在右)

中间往两边跳

  1. \(y\) 以 \(x\) 为中点进行跳跃,三元组变为:\((x-(y-x),x,z)\implies(2x-y,x,z)\)
  1. \(y\) 以 \(z\) 为中点进行跳跃,三元组变为:\((x,z,z+(z-y))\implies(x,z,2z-y)\)

两边往中间跳

这里方便讨论我们不妨设 \(dis_{1}\) 为 \(x\) 和 \(y\) 之间的距离,\(dis_{2}\) 为 \(y\) 和 \(z\) 之间的距离。

当 \(dis_{1} > dis_{2}\)

  1. \(x\) 以 \(y\) 为中点进行跳跃,三元组变为:\((y,y+dis_{1},z)\implies(y,2y-x,z)\)

当 \(dis_{1} < dis_{2}\)

  1. \(z\) 以 \(y\) 为中点进行跳跃,三元组变为:\((x,y-dis_{2},y)\implies(x,2y-z,y)\)

当 \(dis_{1}=dis_{2}\)

无法继续跳,也就是我们的边界。

好,现在把所有我们已知的条件串起来看:这不就是一棵二叉树吗?

对呀,这就是一棵二叉树(我在说什么

为什么这一定是一棵树呢?想一想就明白了,就像数学中的收敛一样,最后一定会出现 \(dis_{1}=dis_{2}\) 的情况。

而且这棵树是唯一确定的。

那么这道题的答案是什么就很明确了。

首先判断YES或NO的情况我们只需要判断初始状态和目标状态是否在统一棵状态树上即可。

最小的步数就是他们两个在树上的距离。

暴力肯定是不可取的。

但是我们可以通过模拟暴力的情景来得到优化的策略。

比如我们思考一个数据:\(x,y,z\)。

其中 \(y\) 是一个 远大于 \(x\) 的数。

方便起见我们令 \(z=y+1\)

暴力此时会不停的让 \(z\) 以 \(y\) 为中点跳。

此时我们回顾一下题面:

棋子之间互相没有差别。

没错,每颗棋子之间其实是没有任何差别的。

打个比方说,现在 \(z\) 以 \(y\) 为中点进行了跳跃,其本质就是 \(z\) 和 \(y\) 一起往左平移了 \(z-y\) 步。

这就意味着,我们不需要老老实实的每次都跳,我们可以直接获得 \(z\) 跳跃的次数即 \((y-x)\div(z-y)\) 次。

再推一下就是欧几里得最大公约数的形式了,也就是说我们在 \(log_{2}\) 的复杂度解决了这个问题。

最后二分一下到LCA的距离,这道题就被你暴切啦

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue> using namespace std; int a, b, c;
int x, y, z; void sort(int& x, int& y, int& z) {
vector < int > vec;
vec.push_back(x);
vec.push_back(y);
vec.push_back(z);
sort(vec.begin(), vec.end());
x = vec[0], y = vec[1], z = vec[2];
} void Initialization() {
scanf("%d %d %d", &a, &b, &c);
scanf("%d %d %d", &x, &y, &z);
sort(a, b, c);
sort(x, y, z);
} int GetRoot(int& x, int& y, int& z) {
int dis1 = y - x;
int dis2 = z - y;
if (dis1 ^ dis2) {
int temp;
if (dis1 < dis2) {
temp = dis2 / dis1;
if (!(dis2 % dis1)) --temp;
x += temp * dis1;
y += temp * dis1;
}
else {
temp = dis1 / dis2;
if (!(dis1 % dis2)) --temp;
z -= temp * dis2;
y -= temp * dis2;
}
return temp + GetRoot(x, y, z);
}
else return 0;
} void ArriveK(int& x, int& y, int& z, int key) {
int dis1 = y - x;
int dis2 = z - y;
if (dis1 < dis2) {
int temp = dis2 / dis1;
if (!(dis2 % dis1)) --temp;
if (temp >= key) {
x += key * dis1;
y += key * dis1;
}
else {
x += temp * dis1;
y += temp * dis1;
ArriveK(x, y, z, key - temp);
}
}
else {
int temp = dis1 / dis2;
if (!(dis1 % dis2)) --temp;
if (temp >= key) {
z -= key * dis2;
y -= key * dis2;
}
else {
z -= temp * dis2;
y -= temp * dis2;
ArriveK(x, y, z, key - temp);
}
}
} signed main() {
Initialization();
int a0 = a, b0 = b;
int c0 = c, x0 = x;
int y0 = y, z0 = z;
int rt1 = GetRoot(x0, y0, z0);
int rt2 = GetRoot(a0, b0, c0);
if (a0 ^ x0 || b0 ^ y0 || c0 ^ z0) return puts("NO") & 0;
if (rt1 < rt2) ArriveK(a, b, c, rt2 - rt1);
else ArriveK(x, y, z, rt1 - rt2);
int l = 0, r = min(rt1, rt2);
while (l < r) {
int mid = (l + r) >> 1;
a0 = a, b0 = b, c0 = c;
x0 = x, y0 = y, z0 = z;
ArriveK(x0, y0, z0, mid);
ArriveK(a0, b0, c0, mid);
if (x0 == a0 && y0 == b0 && z0 == c0)
r = mid;
else
l = mid + 1;
}
printf("YES\n%d\n", max(rt1, rt2) - min(rt1, rt2) + (l << 1));
return 0;
}

Solution -「洛谷 P1852」跳跳棋的更多相关文章

  1. Solution -「洛谷 P4372」Out of Sorts P

    \(\mathcal{Description}\)   OurOJ & 洛谷 P4372(几乎一致)   设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...

  2. Note/Solution -「洛谷 P5158」「模板」多项式快速插值

    \(\mathcal{Description}\)   Link.   给定 \(n\) 个点 \((x_i,y_i)\),求一个不超过 \(n-1\) 次的多项式 \(f(x)\),使得 \(f(x ...

  3. Solution -「洛谷 P4198」楼房重建

    \(\mathcal{Description}\)   Link.   给定点集 \(\{P_n\}\),\(P_i=(i,h_i)\),\(m\) 次修改,每次修改某个 \(h_i\),在每次修改后 ...

  4. Solution -「洛谷 P6577」「模板」二分图最大权完美匹配

    \(\mathcal{Description}\)   Link.   给定二分图 \(G=(V=X\cup Y,E)\),\(|X|=|Y|=n\),边 \((u,v)\in E\) 有权 \(w( ...

  5. Solution -「洛谷 P6021」洪水

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个点的带点权树,删除 \(u\) 点的代价是该点点权 \(a_u\).\(m\) 次操作: 修改单点点权. ...

  6. Solution -「洛谷 P4719」「模板」"动态 DP" & 动态树分治

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个结点的带权树,\(m\) 次单点点权修改,求出每次修改后的带权最大独立集.   \(n,m\le10^5 ...

  7. Solution -「洛谷 P5236」「模板」静态仙人掌

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 个点 \(m\) 条边的仙人掌,\(q\) 组询问两点最短路.   \(n,q\le10^4\),\(m\ ...

  8. Solution -「洛谷 P4320」道路相遇

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 个点 \(m\) 条边的连通无向图,并给出 \(q\) 个点对 \((u,v)\),询问 \(u\) 到 ...

  9. Solution -「洛谷 P5827」边双连通图计数

    \(\mathcal{Description}\)   link.   求包含 \(n\) 个点的边双连通图的个数.   \(n\le10^5\). \(\mathcal{Solution}\)    ...

  10. Solution -「洛谷 P5827」点双连通图计数

    \(\mathcal{Description}\)   link.   求有 \(n\) 个结点的点双连通图的个数,对 \(998244353\) 取模.   \(n\le10^5\). \(\mat ...

随机推荐

  1. 非 root 用户手动编译安装 GCC

    我们知道,关于 GCC 在 CentOS 下通过 yum 安装默认版本号,CentOS 5 是 4.1.2:CentOS 6 是 4.4.7:CentOS 7 是 4.8.3.很多时候在编译安装软件都 ...

  2. Linux服务器设置虚拟内存

    cd /usrsudo mkdir swapcd swapsudo dd if=/dev/zero of=/usr/swap/swapfile bs=1M count=4096du -sh /usr/ ...

  3. 高精度减法(模板yxc)

    #include <bits/stdc++.h> using namespace std; bool cmp(vector<int> &A, vector<int ...

  4. NVIDIA Maxine Video Effects SDK 編程指南 - 实践小记

    NVIDIA Maxine Video Effects SDK 編程指南 - 实践小记 本篇博客重点只说Video Effect的部分,此外还有Audio Effect的部分.还有AR部分,不在本篇范 ...

  5. Custom directive is missing corresponding SSR transform and will be ignored

    背景 最近在给业务组件库集成指令库,将各个项目中常用的指令如一键复制.元素和弹窗拖拽等封装到一起,进行统一发版维护. 业务组件库项目架构采用的是pnpm+vite+vue3+vitepress,其中v ...

  6. PHP支付接口签名生成数据

    <?php //作者主页 https://www.woailunwen.com $pay_memberid = '商户号'; $pay_orderid = '订单号'; $pay_amount ...

  7. 记一次线上bug:crontab 被意外清空

    记一次线上bug:crontab 被意外清空 目录 记一次线上bug:crontab 被意外清空 问题概述 问题排查 问题复现 其他测试 总结 又是一次难忘的经历. 问题概述 同事反馈,某台服务器的c ...

  8. 安装Hadoop单节点伪分布式集群

    目录 安装Hadoop单节点伪分布式集群 系统准备 开启SSH 安装JDK 安装Hadoop 下载 准备启动 伪分布式模式安装 配置 配饰SSH免密登录本机 测试启动 单节点安装YARN 伪分布式集群 ...

  9. 【阅读笔记】低照度图像增强-《Adaptive and integrated neighborhood-dependent approach for nonlinear enhancement of

    本文介绍改进INDANE算法的低照度图像增强改进算法(AINDANE算法),<Adaptive and integrated neighborhood-dependent approach fo ...

  10. C语言基础-基础指针

    文章目录 指针 前言 1.什么是指针 2.指针的使用 (1)指针的定义 (2)指针的赋值 (3)指针类型 (4)如何使用指针 3.野指针 (1)导致野指针的原因 ① 未初始化指针 ②指针越界访问 ③指 ...