NOIP2012提高组 开车旅行 题解

来源:互联网 发布:网络测试工程师面试题 编辑:程序博客网 时间:2024/04/30 02:18

题目连接:https://www.luogu.org/problem/show?pid=1081

题目描述:

小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为Hi,城市 i 和城市 j 之间的距离 d[i,j]恰好是这两个城市海拔高度之差的绝对值,即d[i,j] = |Hi− Hj|。

旅行过程中,小 A 和小 B 轮流开车,第一天小 A 开车,之后每天轮换一次。他们计划选择一个城市 S 作为起点,一直向东行驶,并且最多行驶 X 公里就结束旅行。

小 A 和小 B的驾驶风格不同,小 B 总是沿着前进方向选择一个最近的城市作为目的地,而小 A 总是沿着前进方向选择第二近的城市作为目的地(注意:本题中如果当前城市到两个城市的距离相同,则认为离海拔低的那个城市更近)。

如果其中任何一人无法按照自己的原则选择目的城市,或者到达目的地会使行驶的总距离超出 X 公里,他们就会结束旅行。

在启程之前,小 A 想知道两个问题:

1.对于一个给定的 X=X0,从哪一个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值最小(如果小 B 的行驶路程为 0,此时的比值可视为无穷大,且两个无穷大视为相等)。

2 .  如果从多个城市出发,小 A 开车行驶的路程总数与小 B 行驶的路程总数的比值都最小,则输出海拔最高的那个城市。对任意给定的 X=Xi和出发城市 Si,小 A 开车行驶的路程总数以及小 B 行驶的路程总数。

【数据范围】对于100%的数据,有1≤N≤100,000,1≤M≤10,000,-1,000,000,000≤Hi≤1,000,000,000,0≤X0≤1,000,000,000,1≤Si≤N,0≤Xi≤1,000,000,000,数据保证 Hi互不相同。


总思想:二分

f[i][j]表示从节点i出发,A和B总共走2^j步的一些状态,比如:

f[i][j][0]表示2^j后,A总共走的距离

f[i][j][1]表示2^j后,B总共走的距离

f[i][j][2]表示2^j后,A+B总共走的距离

f[i][j][3]表示2^j后,到达的节点坐标

倍增方程f[i][j] = f[f[i][j-1][3]][j-1]   即从i出发,先走2^j-1步,到达点x,然后继续走2^j-1步,总共走了2^(j-1)+2^(j-1)=2^j步。

这样只要求出f[i][0]及f[i][1]就可以求出所有的f[i][j]。(这道题,f[i][0]有点特别,我这里专指A走1步,所以是从f[i][1]推倒到f[i][j]的,而不是f[i][0]开始推倒)


接下来就是预处理了:如何快速求出每个点出发的最近点以及次近点?

按高度快排,同时记录编号为i的城市,最后在快排序列的什么位置。

假设这个排序序列是a1,a2,a3,…an。则,对于ai这个城市,如果所有编号<ai的城市最近点以及次近点都已经求出,并且不在这个排序序列中,那么城市ai的最近点以及次近点一定在ai-2 ai-1ai+1ai+2中的两个。将这个4个城市进行判断,得出解以后,其实这个城市ai已经没用了,可以从序列中删除以保证后面能也同样处理。

所以我们只需将这个快排以后的序列存储到链表中,并且从编号小的点处理到编号大的点,边处理边删除即可求出所有城市的最近点以及次近点。复杂度O(4n)

预处理复杂度O(4n+nlogn),完全可以接受并且很理想。


接下来考虑如何处理问题1:

其实很简单,遍历所有城市,计算出以城市i出发行走X0距离,小A及小B行走的距离差即可。

假设行走X0距离,AB总共需开T次车,则即是如何快速求这个T的问题,因为求出来以后直接用之前通过倍增得到的状态数组就可以算出需要的距离差了。

不妨将T看做一个二进制数,则就是如何快速从T转成二进制的问题了,因为f数组就是存了二进制下,二进制各位的状态。所以logN的代价内就能求出这个T,因为最多就是走N步。所以第一个问题的复杂度是O(NlogN)


接下来考虑如何处理问题2:

第二问只是问题比较多而已啦,但是每个小问题和第一问没什么区别,而且复杂度更低。所以只需求解这个M个问题就行了,O(MlogN)。




0 0
原创粉丝点击