Luogu P2678跳石头

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\n",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;
}
posted @ 2019-04-12 20:42  Zforw  阅读(52)  评论(0编辑  收藏  举报