stone

题目的大概意思是:在一条道路上有N个石头,现在要移走M个石头,问移走之后剩下的石头中的最小的距离最大是多少。

首先,根据题目,以及修改数据发现,如果移走的石头越多,那么答案就会越大。从这里就证明了答案是具有单调性的。根据这一点,那么答案就可以用二分答案的方法来求出。

首先,每一个答案都需要验证需移走的石头数是多少,那么,到底要怎么移动,才能让移走的数量最少呢?

例如样例2 11 14 17 21,先实验移走2个到所有石头间的距离都大于12,可以发现,每一次移动,都是移走当前距离与前面一个小于12的。如果移走的是前面的那一个,就会有一些缺陷:你不知道后面会有哪些石头与它的距离是小于12的,如果距离已经是小于12了,而且是最后一个,那么这一种移动方案也不成立。根据贪心的思想来解释,既然前面的已经达到了这个距离,我再增大这个距离对我也没有什么益处,反而移走当前这一个,后面原本小于12的距离也可能会变得大于12,这样要移走的数量自然就少了。这样就可以得到一个最优方案。所以,自然是这样移动是最好的。

算出来移动的个数之后,就可以判断,如果移走的个数比m大,就证明答案要达到这个距离是不可能的事,自然答案就会比当前测试的答案小。否则就可能比这一个大。注意,在二分的时候,也要注意几点:必须要让二分区间达到(】,即右边的一定不成立,而左边的一定成立,而不是让最左点和最右点都能成立,这样二分出来的答案自然就容易不正确。(CCF给出的数据表示,就算没有这么严格,同样能对;但是,如果数据挑一些很困难的数据,答案自然就错了)最后二分出来的答案自然就是左端点(右端点不成立)。

以下为程序:

#include<stdio.h>

#include<stdlib.h>

 

int n,m;

int a[100000];

 

bool _check(int len)

{

      int last=0,move_num=0;

      for(int i=0;i<n;i++)

      {

           if(a[i] - last < len) move_num++;

             else last = a[i];

      }

     

      return move_num <= m;

}

 

int main()

{

      freopen("stone.in","r",stdin);

      freopen("stone.out","w",stdout);

     

      int l;

      scanf("%d%d%d",&l,&n,&m);

      for(int i=0;i<n;i++) scanf("%d",&a[i]);

      a[n]=l;n++;

     

      int lowerlim=0,upperlim=l+1;

      while(lowerlim+1 < upperlim)

      {

           int middle=(upperlim+lowerlim) >> 1;

          

           if( _check(middle) ) lowerlim=middle;

             else upperlim=middle;

      }

     

      printf("%d\n",lowerlim);

      return 0;

}

最后再说一句,因为二分用递归容易栈溢出(虽然只有50次),所以要用迭代。而且因为可以从起点跳到第一个石头或最后一个石头跳到终点,所以这个也需要算上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值