一年一度的“跳石头”比赛又要开始了!
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 n 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 m 块岩石(不能移走起点和终点的岩石)。
输入文件第一行包含三个整数 l,n,m,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。
接下来 n 行,每行一个整数,第 i 行的整数 di(0 < di < l)表示第i块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
输出文件只包含一个整数,即最短跳跃距离的最大值。
25 5 2 2 11 14 17 21
4
对于20%的数据,0≤M≤N≤10。 对于50%的数据,0≤M≤N≤100。
对于50%的数据,0≤M≤N≤100。
对于100%的数据,0≤M≤N≤50,000,1≤L≤1,000,000,000。
凡是要求“最小XX的最大值”或者“最大XX的最小值”,用二分答案法,即已知答案范围,二分验证答案,直到找到最优解。 对本例而言,要求“最短跳跃距离的最大值”,每次只能跳到相邻的石头上,移走不超过一定数量的石头(起点终点除外)使得最短跳跃距离最大。 根据物理意义,最短跳跃距离的最大值的范围自然是 0 到 l 。然后我们设二分区间 [L, R] = [0, l] ,每次都取 M = (L + R) / 2 ,M 代表假设最短跳跃距离的最大值。而 num 函数返回当要求最短跳跃距离的最大值超过 M 需要移走的石头数量。如果需要移走太多石头(超过上限 m),就要缩小右端点的范围:令 R = M - 1 ;如果需要移走的石头数量不超过限制 m ,就需要考察更大的 M 值,来判断本次找到的 M 是不是要求的最大值。 注意,从起点开始跳完 n 块石头后,还需要跳一次到终点,这段距离也要补上,即 d[++n] = l 。 而 num 函数中,设 c 表示需要移走的石头的数量,s 表示选择的石头。然后对第 1 ~ n 块(注意 ++n)石头分别验证,如果当前正在考察的第 i 块石头与被选择的第 s 块石头(开始时 s = 0)的距离大于要求的最短跳跃距离的最大值 a(将 M 传入 a),就标记这块石头,且这块石头不用移动。接下来只需验证剩余的石头与当前这块被标记的石头的距离是否符合要求就可以了。 注意,跳到最后一块石头时,还要再跳一次到终点,最后的石头到终点这段距离也需要验证是否过短。为了验证这段距离,在输入完数据以后需要补充 d[++n] = l 。在循环中,当这段距离也太短时,终点的石头也需要被移走,返回的需要移走的石头数量也会多 1 。可以验证,这要么使 num(M) > m ,即尝试考察的最短跳跃距离的最大值 M 太大,同样需要缩小区间;要么使得 num(M) <= m ,因为题目并没有要求一定要移走 m 块石头,所以此时返回的值 多了 1 对后续并没有影响。 对离散闭区间 [L, R] 二分,最终一定会使 L = R ,这里不予证明。 注意 num 返回的是当最短跳跃距离的最大值大于 M 时需要移走的石头的数量。当 M = L = R 时,显然答案只能是 M ,那么实现最短跳跃距离的最大值大于 M 需要撤走的石头一定会多于上限 m ,从而导致 R = M - 1 ,使 R < L ,所以最终输出的答案是 L 。
