noip2015跳石头

来源:互联网 发布:linux下touch命令 编辑:程序博客网 时间:2024/05/17 08:33

noip 2015 跳石头

思考了许久 最终挑了如下一篇题解给自己解答

#include<cstdio>

#include<cstring>
using namespace std; 
const int maxn=50010;
//n,m,L的意义和题目描述中的一样,a[]表示每个石头到起点的距离,方便起见,将终点补充为最后一块石头
int n,m,L;
int a[maxn];
//二分了最短跳跃距离 mid之后,开始检查这个答案mid能不能满足至多抽走m块石头
bool check(int mid){
 //last表示上一块没有被抽走的石头离起点的距离
 int last=0,cnt=0;
 for(int i=1;i<=n;i++){
  //如果两点之间的距离比跳跃距离短,那么就需要把这一块石头拿走,不然的话就可以不用管。
  //当然如果i==n也就是终点的时候是不能拿走终点的,但是这个时候拿掉前一个石头也一定能达成目的,所以不管怎样只需要拿掉一个石头。
  //如果不用拿掉的话,上一块没有抽走的石头就是当前这一块了。
  if(a[i]-last<mid) cnt++;
  else last=a[i];
 }
 //如果必须要拿掉的石头数目<=m个,说明二分出的最短距离可以接受,返回true
 if(cnt<=m) return true;
 return false;
}
 
int main(){
 int ans; 
 scanf("%d%d%d",&L,&n,&m);
 n++;a[n]=L;
 for(int i=1;i<n;i++) scanf("%d",&a[i]);  
 int l=0,r=a[n],mid;
 while(r-l>1){
  mid=(l+r)>>1;
  //如果这个值可以接受,那么比它小的值都可以接受,二分的下界就可以变成这个新的值
  //如果不能接受,那么比它大的值也不能接受,二分的上界变成这个新的值
  if(check(mid)) l=mid;
  else r=mid;
 } 
 //当然如果最后区间还剩下两个的时候,有可能上界也是可以接受的。[其实这种情况只发生在a[n]为最大距离时]
 if(check(r)) ans=r;
 else ans=l;
 printf("%d",ans);
 return 0;
}
原创粉丝点击