poj 3258河石(二分的妙用)

来源:互联网 发布:达达主义摄影知乎 编辑:程序博客网 时间:2024/06/13 14:57

Every year the cows hold an event featuring a peculiar version of hopscotch that involves carefully jumping from rock to rock in a river. The excitement takes place on a long, straight river with a rock at the start and another rock at the end, L units away from the start (1 ≤ L ≤ 1,000,000,000). Along the river between the starting and ending rocks, N (0 ≤ N ≤ 50,000) more rocks appear, each at an integral distance Di from the start (0 < Di < L).

To play the game, each cow in turn starts at the starting rock and tries to reach the finish at the ending rock, jumping only from rock to rock. Of course, less agile cows never make it to the final rock, ending up instead in the river.

Farmer John is proud of his cows and watches this event each year. But as time goes by, he tires of watching the timid cows of the other farmers limp across the short distances between rocks placed too closely together. He plans to remove several rocks in order to increase the shortest distance a cow will have to jump to reach the end. He knows he cannot remove the starting and ending rocks, but he calculates that he has enough resources to remove up to M rocks (0 ≤ M ≤ N).

FJ wants to know exactly how much he can increase the shortest distance before he starts removing the rocks. Help Farmer John determine the greatest possible shortest distance a cow has to jump after removing the optimal set of M rocks.

Input
Line 1: Three space-separated integers: L, N, and M
Lines 2.. N+1: Each line contains a single integer indicating how far some rock is away from the starting rock. No two rocks share the same position.
Output
Line 1: A single integer that is the maximum of the shortest distance a cow has to jump after removing M rocks
Sample Input
25 5 2
2
14
11
21
17
Sample Output
4

题意:牛要到河对岸,在与河岸垂直的一条线上,河中有N块石头,给定河岸宽度L,以及每一块石头离牛所在河岸的距离,

      现在去掉M块石头,要求去掉M块石头后,剩下的石头之间以及石头与河岸的最小距离的最大值。

这个二分也是醉了,太神奇。平时都是l小于r,现在是用到了(l<=r)具体问题具体分析。
首先要求的是最小跳越值的最大化。这个最小跳越值大于0小于总长度,先把石头排序,二分m,如果能这个跳跃长度能跳过的石头比要摘除的石头多,那么尝试把m变小,如果这个能跳过的石头比要摘掉的石头少,那么把这个值提升,如果相等,也提升,最后得到m由于 l=m+1,而r=m退出,或者r=m-1,而l=m退出。因为这是用另一个变量代表中值,即能跳过去的石头的数量,而不是以前的如果与中值相等就退出,这里用第三方作为中值,而且围绕着上下波动。
最后的结果肯定是跳过的石头数量相等,然后找边界。因为最后l会比r大,所以返回r。这些用第三方作为中值比较,用while(l<=r)这样的二分最合适,因为到达中值,无需跳出。
难点,边界的起点终点,统计的条件。

#include <stdio.h>  #include <algorithm>  #include <iostream>  #include <queue>  #include <string.h>  using namespace std;int L,N,M;int d[50005];bool cmp(int a,int b){    return a<b;}int BSearch(int l,int h,int k){    int m,last,cnt;    while(l<=h)    {        m=(l+h)>>1;        last=cnt=0;        for(int i=1;i<=N+1;i++)        {            if(m>=d[i]-d[last]) cnt++;  //m是能跳过这么多石头里面,最小跳越值最大的,难点            else last=i;           }        if(cnt>k) h=m-1; //说明这个最小跳越值可以跳的石头太多,需要减少最小跳越值。因为这个不是最小跳越值。                          //如果超过最小间距的石头比需要的多,那么最小间距可以更小。        else l=m+1;    //如果cnt不够或者刚好满足,那么m可以更大,    }                  //因为即使是跳过k个石头也不定是最大的,所以增加最小跳越值。    return l;}int main(){    scanf("%d%d%d",&L,&N,&M);    d[0]=0;    d[N+1]=L;//难点    for(int i=1;i<=N;i++)        scanf("%d",&d[i]);    sort(d+1,d+N+1,cmp);    printf("%d\n",BSearch(0,L,M) );}
0 0