NOIP2012提高组 开车旅行 解题报告

7 篇文章 0 订阅
1 篇文章 0 订阅

开车旅行

题目描述

这里写图片描述
这里写图片描述

样例输入

这里写图片描述

样例输出

这里写图片描述

70分算法

暴力预处理出对于每一个点他右边最近、次近的点的编号,对于每一个询问,暴力模拟开车过程即可。

100算法

和上面一样我们得预处理出每一个点最近、次近的点得编号,但我们不可以使用 O(n2) 的算法。

  • 预处理方法一:线段树。线段树维护三个值,区间内最小值、最大值、数的个数。从右往左找( n ~1),当找到第 i 个点时,第i+1个点到第 n 个点的高度值已经更新过了线段树。通过线段树找出高度比Hi大的最小、次小值,以及找出高度比 Hi 小的最大、次大值,便可以更新第 i 个点的最近、次近的点的编号了。因为Hi的值可能很大,会空间超限,所以做之前需要离散化一次。

  • 预处理方法二:双向链表。相比线段树,不需要离散化,但是细节多,调试较麻烦。先将 Hi 从小到大排序,将两两相邻的两个点连起来。再从前往后枚举 i ,对于每一个点i,找出它后面连着的两个点(即为大于 Hi 的最小、次小点)和找出它前面连着的两个点(即为小于 Hi 的最大、次大点),这样就可以更新出第 i 个点的最近、次近点。之后,再将第i的点从链表中删去,将其前后的两个元素相连起来。

  • 预处理完毕后,就可以开始求答案了。
    如果 A x点开车至 y 点,然后B y 点开车到z点,则我们视为 x z来了一条边,我们称从 x 开车到z成为“一轮”。
    接下来我们要求出在点 i 开车经过了2j轮后到达的点的编号,设其为 m [i][ j ]。首先,从后往前枚举i,我们可以通过预处理出来的数据求出 m [i][ 0 ],之后对于每一个m[ i ][j]我们可以从 m [i][ j -1]转移过来。(设k= m [i][ j -1]),则m[ i ][j]= m [k][ j -1],即等于i跳了两次2j1轮,即 2j 轮,跳到不能跳为止。同时处理一下 A 开过的路程和B开过的路程。

  • 上面做的一切都是为了接下来的答案求值。接下来要介绍一种算法——倍增。倍增,顾名思义,就是成倍成倍的增长。第一次先开 217 轮(最多),第二次再开 216 轮,然后 215 轮、 214 轮……可以跳 2j 轮便跳(即不会越界),不行就不跳。此时开车开到再也开不了为止,这个点便是终点。这样就可以在很短的时间内求出答案。

  • 注:答案会很大,需要开int64(long long)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值