Description:
一年一度的“跳石头”比赛又要开始了!这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。
Analysis:
一般最小值最大的问题都是二分答案,初始时区间答案可能在的区间[1,L + 1],不断二分,判断中间点 mid 是否可行。至于判断,因为答案是最短的距离,所以要使所有点之间的距离大于等于 mid,从第一个点到第 n+1个点扫一遍,如果一个点到上一个点之间的距离小于mid,那么就将该点删去,最后看删去的点是否大于m。如果mid可行,那么可能会有更优的解,也就是说mid可以更大,将左端点右移;否则,删去的点太多,mid不是合法解,将右端点左移。
Code
#include<cstdio>
#define N 50005
using namespace std;
int d[N],L,n,m;
bool Check(int x)
{
int last = 0,cnt = 0;
for(int i = 1;i <= n + 1;++i){
//each distance >= x
if(d[i] - d[last] < x) ++cnt;
else last = i;
}
if(cnt > m) return 0;
return 1;
}
void solve()
{
int lb = 0,ub = L + 1;
while(lb + 1 < ub){
int mid = (lb + ub)/2;
//mid could be larger
if(Check(mid)) lb = mid;
else ub = mid;
}
printf("%d
",lb);
}
int main(){
scanf("%d %d %d",&L,&n,&m);
for(int i = 1;i <= n;++i){
scanf("%d",&d[i]);
}
d[n + 1] = L;//Attention
solve();
return 0;
}