Description
有一条宽度为L(1≤L≤ 1,000,000)的河。河中间有N(0≤N≤20000)块石头,青蛙从河西岸经过这N个石块后,顺利跳到了河的东岸。设河中间每个石块距离西岸的距离为Di(其中Di大于0小于L)。注意:Di是距离起始河岸的距离。
小明闲着没事,想移掉河中间的M(0≤M≤N)个石块,让一些石块之间的距离增大一点,好叫青蛙没那么容易跳到对岸。
由于移除M个石块的方法有多种,所以在移除石块之前,小明想知道如果他恰好移除河中M个石块后,青蛙跳的最短距离的最大值可以达到是多少?(青蛙跳一段的距离:西岸与河中第一个石块距离、河中相邻石块的距离、最后一个石块与东岸的距离。青蛙每次都是从一个石块跳到与它相邻的下一个石块)。
Input
多组输入。第一行顺序输入L, N和M。接下来输入N个正整数(不保证有序),表示N个石块距离起始河岸的距离。
Output
对于组输入,输出移除M个石块后,整个跳跃过程中最短距离的最大值。
Sample Input
25 5 2
2
14
11
21
17
Sample Output
4
Hint
在移除石块之前,跳跃过程中的最小间距2(起点距第1个石块)。移除距离起始岸为2和14的石块后,最小间距就为4了。(0 – 11 – 17 – 21 – 25 )。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int size = 50002;
int D[size],L,N,M;
int minl,maxl, ans;
bool Ok(int x)
{
int tot = 0,i = 0, t = 0;
while (i<=N)
{
tot = D[i++];
while (i <= N && tot < x)
{//不能小于x, tot小于枚举的x,必须合并
tot += D[i++];
t++;//拿掉一块石头,合并一次
}
if (t > M) return 0;//要使用t次才能满足答案为x的条件,超过了M,不符合等于M的条件,返回0
}
//加上,这一句
//此时tot是最后几块合并的值,如果他小于枚举的答案x
//且t==M(也就是你之前把可以拿去M块石头的机会都用光了),
//这种情况tot为最小值,所以x不符合条件
if (tot < x && M == t) return 0;
return 1;
}
void Binary()
{
int l = minl, r = maxl, m;
while (l <= r)
{
m = (l+r)/2;//
if (Ok(m)) l = m + 1, ans = m;/*继续枚举更大的答案(最小值最大,
能够越大尽量越大),并且记录当前可行的答案 */
else r = m - 1;//枚举更小的答案
}
}
int main()
{
int i, j, k;
//freopen("B.in","r",stdin);
//freopen("tmp.out","w",stdout);
while (scanf("%d%d%d",&L,&N,&M)!=EOF)
{
for (i = 0; i < N; i++)
scanf("%d",&D[i]);
sort(D,D+N);//排序,计算石头之间的间距
D[N] = L;//最后块(也就是对岸)距离起点的距离为L
minl = maxl = ans = D[0];
for (i = N; i > 0; i--)
{
D[i] = D[i]-D[i-1];//求石头间距
//printf("%d ",D[i]);
//if (D[i] == 0) printf("AAA\n");
if (D[i]<minl) minl = D[i];//找出所有间距中的最小值
maxl += D[i];//最大间距就是Di之和,也就是L
}
Binary();//二分枚举答案
printf("%d\n",ans);
}
return 0;
}