题目链接:River Hopscotch - POJ 3258 - Virtual Judge
题意:
每年奶牛们都要举办各种特殊版本的跳房子比赛,包括在河里从一块岩石跳到另一块岩石。这项激动人心的活动在一条长长的笔直河道中进行,在起点和距离起点 L 远的终点各有一块岩石 (1 ≤ L ≤ 10^9)。在起点和终点之间,有 N 块岩石 (0 ≤ N ≤ 50000),每块岩石与起点的距离分别为 Di (0 < Di < L)。
在比赛过程中,奶牛轮流从起点出发,尝试到达终点,每一步只能从一块岩石跳到另一块岩石。当然,实力不济的奶牛无法抵达终点,在河中间就退出比赛了。
农夫约翰为他的奶牛们感到自豪并且年年都观看了这项比赛。但随着时间的推移,看着其他农夫的胆小奶牛们在相距很近的岩石之间缓慢前行,他感到非常厌烦。他计划移走一些岩石,使得从起点到终点的过程中,最短的跳跃距离最长,跳到终点的距离不计入。他可以移走除起点和终点外的至多 M 块岩石 (0 ≤ M ≤ N)。
请帮助农夫约翰确定:移走这些岩石后,最短跳跃距离的最大值是多少?
输入
第 1 行包含以单个空格分隔的三个整数 L, N, M。
第 2 到 N + 1 行,每行一个整数,表示每个岩石与起点的距离。不会有两个岩石出现在同一个位置。
输出
输出一个整数,即最短跳跃距离的最大值。
示例输入
25 5 2 2 14 11 21 17
示例输出
4
分析:简单分析我们能发现答案具有单调性,现在假设我们能够去掉的石头数目不确定,也就是说如果最短跳跃距离为x所需去掉的石头数为y,那么对于任意最短跳跃距离为u(u>x)的方案最少所需去掉的石头数v一定大于等于y,所以我们就可以根据这个二分最短距离,每次通过比较需要去掉的石头数与给定可以去掉的石头数来判断最短距离偏大还是偏小,具体比较方式如下:
对于最短跳跃距离为x所需去掉的石头数为y,若y<=m,也就是说我们还能通过多去掉几块石头来增大这个最短距离,所以就是x小于等于正确答案,反之就是大于正确答案
注意细节:当最短跳跃距离为x所需去掉的石头数为y,若y=m,则x未必为答案,实际上此时的x是小于等于正确答案的
下面是代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=5e4+10;
int a[N],n,m,L;
bool check(int x)
{
int cnt=0,r=0;//记录最少需要移走的石头数,r为上一块石头的位置
for(int i=1;i<=n+1;i++)
{
if(a[i]-r<x) cnt++;//一旦距离小于x则该石头就要被移除
else r=a[i];
}
if(cnt<=m) return true;//答案偏小
return false;
}
int main()
{
cin>>L>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
a[n+1]=L;
sort(a+1,a+n+1);
int l=1e9+10,r=1e9+10,mid;
for(int i=1;i<=n+1;i++)
l=min(l,a[i]-a[i-1]);
while(l<r)
{
mid=l+r+1>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
printf("%d",l);
return 0;
}