P1852 [国家集训队]跳跳棋

题目背景

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

题目描述

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

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

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

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

输入输出格式

输入格式:

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

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

输出格式:

如果无解,输出一行NO。

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

输入输出样例

输入样例#1: 复制

1 2 3
0 3 5
输出样例#1: 复制

YES
2

说明

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

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

100% 绝对值不超过10^9


Solution

然而并不想写solution....

是一道建模题,谁能想到这道题和树可以扯上关系????

把起点和终点状态拟成树上的两个节点,就像树上求链的长度一样找lca并且把两个节点到lca的距离加起来得到答案。

听起来好玄乎??

更玄乎的是这种找lca的方法和倍增惊人地相似!

想要找到中间作为lca的转折状态,一步一步跳显然不行。由此观察题目本身的性质,给出的三个棋子是完全相同的,那么把一个作为中轴跳相当于把这两个棋子一起平移他们之间的距离。

这样可以快速地找到某一状态一直跳到不能跳时每个棋子的位置。所以首先判断如果给出的两个状态的最终状态不相同,那么输出‘NO’

所以我们还发现,两种状态跳到他们最终状态的步数的差就是它们‘深度’的差,就像倍增求lca先要把深度调成一样再一起往上跳。

所以先处理出以上需要的东西,有点像辗转相除??每次都尽量跳到不能跳,然后交换继续跳。

将两个状态深度调到一样后,一起向上跳的步数就可以用二分,每次check往上跳看是否跳到一样。

二分出的答案要乘2(链)加上深度调到一样的答案即可。

Code

#include<bits/stdc++.h>
#define LL long long
using namespace std; LL dep1, dep2, a, b, c, x, y, z, ans; LL get_root(LL a, LL b, LL c, LL &dep, LL &l) {
LL d1 = b - a, d2 = c - b;
while(d1 != d2) {
if(d2 > d1) {
LL s = d2 / d1, dis = d2 % d1;
if(!dis) {
dep += s - ;
l = d1; return a + (s - ) * d1;
}
dep += s; a += s * d1; b += s * d1;
d2 = dis;
} else {
LL s = d1 / d2, dis = d1 % d2;
if(!dis) {
dep += s - ;
l = d2; return a;
}
dep += s; b -= s * d2; c -= s * d2;
d1 = dis;
}
}
dep = ; l = d1; return a;
} void Swap(LL &a, LL &b, LL &c) {
if(a > b) swap(a, b);
if(a > c) swap(a, c);
if(b > c) swap(b, c);
} void find_fa(LL &a, LL &b, LL &c, LL step) {
while(step) {
LL d1 = b - a, d2 = c - b;
if(d2 > d1) {
LL s = d2 / d1;
if(s >= step) {
a += step * d1; b += step * d1;
return ;
}
a += s * d1; b += s * d1; step -= s;
} else {
LL s = d1 / d2;
if(s >= step) {
c -= step * d2; b -= step * d2;
return ;
}
c -= s * d2; b -= s * d2; step -= s;
}
}
} void solve() {
LL l = , r = min(dep2, dep1);
LL st;
while(l <= r) {
LL mid = (l + r) >> ;
LL aa = a, bb = b, cc = c;
LL xx = x, yy = y, zz = z;
find_fa(aa, bb, cc, mid);
find_fa(xx, yy, zz, mid);
if(aa == xx && bb == yy && cc == zz) st = mid, r = mid - ;
else l = mid + ;
}
printf("%lld", ans + st * );
} int main() {
scanf("%lld%lld%lld%lld%lld%lld", &a, &b, &c, &x, &y, &z);
Swap(a, b, c); Swap(x, y, z);
LL del1, del2;
LL pos1 = get_root(a, b, c, dep1, del1);
LL pos2 = get_root(x, y, z, dep2, del2);
if(del1 != del2 || pos1 != pos2) {
puts("NO"); return ;
}
puts("YES");
if(dep1 > dep2) {
ans += dep1 - dep2;
find_fa(a, b, c, dep1 - dep2);
} else if(dep2 > dep1) {
ans += dep2 - dep1;
find_fa(x, y, z, dep2 - dep1);
}
solve();
}

【洛谷】1852:[国家集训队]跳跳棋【LCA】【倍增?】的更多相关文章

  1. 洛谷 P1852 [国家集训队]跳跳棋 解题报告

    P1852 [国家集训队]跳跳棋 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\), ...

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

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

  3. P1852 [国家集训队]跳跳棋

    P1852 [国家集训队]跳跳棋 lca+二分 详细解析见题解 对于每组跳棋,我们可以用一个三元组(x,y,z)表示 我们发现,这个三元组的转移具有唯一性,收束性 也就是说,把每个三元组当成点,以转移 ...

  4. 模板—点分治A(容斥)(洛谷P2634 [国家集训队]聪聪可可)

    洛谷P2634 [国家集训队]聪聪可可 静态点分治 一开始还以为要把分治树建出来……• 树的结构不发生改变,点权边权都不变,那么我们利用刚刚的思路,有两种具体的分治方法.• A:朴素做法,直接找重心, ...

  5. 洛谷 3379 最近公共祖先(LCA 倍增)

    洛谷 3379 最近公共祖先(LCA 倍增) 题意分析 裸的板子题,但是注意这题n上限50w,我用的边表,所以要开到100w才能过,一开始re了两发,发现这个问题了. 代码总览 #include &l ...

  6. [洛谷P1527] [国家集训队]矩阵乘法

    洛谷题目链接:[国家集训队]矩阵乘法 题目背景 原 <补丁VS错误>请前往P2761 题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入输出格式 输入 ...

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

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

  8. 洛谷P1501 [国家集训队]Tree II(LCT,Splay)

    洛谷题目传送门 关于LCT的其它问题可以参考一下我的LCT总结 一道LCT很好的练习放懒标记技巧的题目. 一开始看到又做加法又做乘法的时候我是有点mengbi的. 然后我想起了模板线段树2...... ...

  9. 洛谷P2619 [国家集训队2]Tree I(带权二分,Kruscal,归并排序)

    洛谷题目传送门 给一个比较有逼格的名词--WQS二分/带权二分/DP凸优化(当然这题不是DP). 用来解决一种特定类型的问题: 有\(n\)个物品,选择每一个都会有相应的权值,需要求出强制选\(nee ...

随机推荐

  1. 安装mysql5.5的时候出现Error Nr.1045

    解决办法: 1.删除注册表几个键值:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Eventlog\Application\MySQL HKEY_L ...

  2. mysql -> 事务&事务锁_09

    事务的特性 redo undo 锁的隔离级别

  3. Unix IPC之基于共享内存的计数器

    目的 本文主要实现一个基于共享内存的计数器,通过父子进程对其访问. 本文程序需基于<<Unix网络编程-卷2>>的环境才能运行.程序中大写开头的函数为其小写同名函数的包裹函数, ...

  4. gtk+学习笔记(六)

    今天用到了滚动窗口和微调按钮,根据网上的信息,简单总结下用法. 滚动窗口只能添加一个控件到其中 scrolled=gtk_scrolled_window_new(NULL,NULL); /*创建滚动窗 ...

  5. 计算a+b

    输入: 1 2 结果: 3 说明:只能输入数字,两数间只有一个空格 代码如下:(vc6编译) #include <stdio.h> #include <conio.h> voi ...

  6. HBase 入门笔记-数据落地篇

    一.前言 关于数据落地方面,HBase官网也有相关介绍.本文主要介绍一下实际工作中涉及的数据存储方面的一些经验和技巧,主要涉及表rowkey设计.数据落地方案 二.表设计 相对于MySQL等关系型数据 ...

  7. Ninject中如果在抽象类中使用了属性注入,则属性必须设置为protected或public

    Ninject中如果在抽象类中使用了属性注入,则属性必须设置为protected或public 不能使用private,否则无法注入成功,会报null异常

  8. 【LOJ】#2123. 「HEOI2015」最短不公共子串

    题解 我们对于B串建出后缀自动机和序列自动机 对于问题1,枚举左端点然后跑后缀自动机,直到不能匹配作为这个左端点的答案 对于问题2,枚举左端点然后跑序列自动机,直到不能匹配 对于问题3,设f[i][j ...

  9. 7-10 守卫棋盘 uva11214

    输入要给n*m的棋盘  均小于10   某些格子有标记  用最少的皇后  辐射到所有的标记 限时 6666ms 用IDA*    时间6000  尴尬. #include<bits/stdc++ ...

  10. Ubuntu16.04下Kylin的安装与配置

    一.系统环境 kylin的安装配置并不像官方文档中描述的那样简单,复杂的原因在于hadoop,hive,hbase,kylin的版本一定要兼容,不然就会出现各种奇怪的错误.以下各软件版本可以成功运行k ...