NKOI3600 河中跳房子游戏

[二分答案]

题目描述

每年,奶牛们都举办一种特殊的跳房子游戏,在这个游戏中,大家小心翼翼地在河中的岩石上跳。这个游戏在一条笔直的河中进行,以一块岩石表示开始,以另一块距离起点L单位长度的岩石表示结束 (1 <= L <= 1,000,000,000)。在这两块岩石中间还有N(0 <= N <= 50,000) 块岩石,每块的位置距离起点是 Di (0 < Di < L)个单位长度。
玩这个游戏的时候,每头牛从开始的那块岩石想办法要跳到表示结束的那块岩石上。中间只能在从某块岩石跳跃到另一块岩石,反复的这样跳。当然,不够敏捷的牛永远跳不到终点,最终只能落入河中。FJ计划移除一些岩石,从而增加奶牛在跳跃时需要的最短距离。他不能移除开始和结束的两块岩石。但是除此之外他可以移除 M (0 <= M <= N)块岩石。FJ 希望知道他能够增加多少最短跳跃距离。求当他移除了M块岩石后,奶牛从开始跳到结束的岩石,每次跳跃的最短距离至多可以增加到多少。

输入格式

行 1: 三个用空格分开的整数,分别是 L, N, 和 M
行 2..N+1: 每行一个整数,表示中间N块岩石的位置,没有两块岩石处于同一位置。

输出格式

行 1: 一个整数表示移除某M块岩石后,相邻岩石间距最小值的最大可能情况。

这道题显然应该先按每个点到起点的距离
增加 最短距离,最小值 最大释放了二分答案的信号。

按照一般步骤:
1.确定上下界
下界就是题目中给出的最短距离,或者直接设为0也可以。
上界就是起点到终点的距离(FJ丧心病狂地拿走了起点到终点间的所有石头)。

2.二分 [OK()函数咋写]
大体的思路很简单:使每个点之间的距离d大于等于二分的答案mid即可。

↓伪代码实现↓

现在已经有了一个排好序的数组dis[N],用来存每个点到起点的距离.
相邻点相减的值,就是d.

由于原数组dis[N]要重复使用,所以另外开一个新数组tmp[N]充当dis[N].
for(int i=1;i<=n;i++)tmp[i]=dis[i];

只要d小于我们二分的答案mid,就继续拿走石头(计数器t加1).

最后判断:如果t>M,那么说明mid大了,减小mid的值才能使移除石头的数量减少;反之,t<=M,就说明mid小了(刚好合适),要增大mid的值才能增加移除石头的数量.

注意
最后判断的时候,每道题都有不同的方法,特别要注意是“<”or”<=”,“>”or”>=”.千万不要错!不然==样例都过不了[一只蒟蒻的心声]==

所以,合起来,代码如下:

#include
#include
#include
#define N 60000
#define LL long long
using namespace std;
LL dis[N],tmp[N];
bool OK(LL mid){
    int t=0;
    for(int i=1;i<=n;i++)tmp[i]=dis[i];
    for(int i=1;i<=n;i++){
        if(tmp[i]-tmp[i-1]1],t++;
        }
    }
    if(t>m)return true;
    else return false;
}
int main(){
    LL L=0,R,n,m,t;
    scanf("%lld%lld%lld",&t,&n,&m);dis[n]=t,R=t;
    for(int i=1;i<=n;i++)scanf("%lld",&dis[i]);
    n++;sort(dis+1,dis+n+1);
    while(L<=R){
        LL mid=(L+R)/2;
        if(OK(mid))R=mid-1;
        else L=mid+1;
    }
    //注意最后还要判断一下L和R哪个才是正解
    //如果OK(L)==true,说明L对应的移除石头的数量比要求的要多,应舍去
    if(OK(L))printf("%lld",R);
    else printf("%lld",L);return 0;
}

你可能感兴趣的:(题解)