题目描述
一年一度的"跳石头"比赛又要开始了!
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 NN 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走MM 块岩石(不能移走起点和终点的岩石)。
输入描述
输入文件第一行包含三个整数 L,N,ML,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。
接下来 NN 行,每行一个整数,第 ii 行的整数 Di(0<Di<L)Di(0<Di<L)表示第 ii 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
其中,0≤M≤N≤5×104,1≤L≤1090≤M≤N≤5×104,1≤L≤109。
输出描述
输出只包含一个整数,即最短跳跃距离的最大值。
示例
输入
25 5 2 2 11 14 17 21
输出
4
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
思路
由题目中的让选手的最短跳跃距离尽可能长,可以考虑用二分法进行求解。
一块块的去遍历石头,最后肯定会超时。所以不妨我们去猜这个最短跳跃距离d。
代码思路
首先,依照题意读入数据。
然后,还需定义一个stone数组,大小为N + 1,索引0处存起点,其余N块存放每块石头距离原点的距离。
下面使用二分法进行d的寻找:
该题二分法是用来猜最短跳跃距离d的,而d的范围是[0,L],所以我们定义变量l = 0,r = L;然后用二分的板子(我用的是l <= r那版)。
那么依据什么标准去调整l,r的大小呢?
因为组委会最多只能移走M块石头,所以我们声明一个变量num——在当前猜测的最短跳跃距离d的前提下,组委会需要移走的石头数。因为要让最短跳跃距离d最大,所以移走的石头数num应该尽可能的多,这样河道中的石头数就少(长度相同,河中石头少了,自然最短的跳跃距离就会变大),在不超过M的前提下。
那么如何去计算num等于多少呢?
我们就需要用到前面定义的stone数组,大小为N + 1,索引0处存起点,其余N块存放每块石头距离原点的距离。
我们将stone数组从索引为1处开始遍历,每遍历一次,我们就判断stone[i] - pos 是否小于我们猜测的最短跳跃距离d,如果小于的话,说明这个石头就可以移走(因为最短跳跃距离d已经是当前河道跳跃距离中最大的了),同时将num ++;如果大于d的话,当前的石头就不能移走,同时把pos变到当前的石头处stone[i]。
当stone数组都遍历完成后,num的值就可以确定了,如果num <= M,返回true,就说明搬走的石头数小于M,即河道中的石头还能再搬走几个,所以在二分板子中,我们还应加大距离d,即l = m + 1,同时定义变量ans记录当前的m,当前的m其实是满足条件的,但是不是最短的跳跃距离而已。如果num > M,我们就返回false,说明石头搬走的太多了,导致河道中的最短跳跃距离太大了,所以减小d的取值,即r = m - 1;
最后,当二分的循环结束的时候,答案已经被存在了ans中,直接输出即可。
代码
import java.util.Scanner;
public class 跳石头 {
static int L,N,M;
static int[] stone;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
L = sc.nextInt();
N = sc.nextInt();
M = sc.nextInt();
stone = new int[N + 1];
for(int i = 1;i <= N;i ++) {
stone[i] = sc.nextInt();
}
int l = 0;
int r = L;
int ans = 0;
while(l <= r) {
int m = (r + l) >>> 1;
if(check(m)) { // m小了
l = m + 1;
ans = m;
}
else {
r = m - 1;
}
}
System.out.println(ans);
}
public static boolean check(int d) {
int num = 0; //num 记录搬走石头的数量
int pos = 0; //当前站立的石头
for(int i = 1;i <= N;i ++) {
if(stone[i] - pos < d) {
num ++; // 第i块石头可以搬走
}
else {
pos = stone[i]; // 第i块石头不能搬走
}
}
if(num <= M) { // 可以搬走的石头数小于最大值M => 参数d小了
return true;
}
else { // 可以搬走的石头数大于最大值M => 参数d大了
return false;
}
}
}