Luogu P2678 [NOIP2015 提高组] 跳石头

题目传送门


题目大意

给你一排 N 块石头,你可以移走 M 块石头(0 \le M \le N \le 500001 \le L \le 10^9),使得最小的两块石头之间的距离尽可能长。

输入格式


第一行包含三个整数 N,M,L,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。

接下来 N 行,每行一个整数,第 i 行的整数 D{i}0 \le D{i} \le L),表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

输出格式


一个整数,即最短跳跃距离的最大值。

输入样例 #1

25 5 2 
2
11
14
17 
21


输出样例 #1


 

4

分析


我们可以换一个思路求解此题:从总距离$L$开始二分最小的最大距离 mid,检测每个 mid 需要搬走的石头数 num,如果满足条件,则尝试更小的 mid,反之同理。

最后是代damn码:


 

#include<bits/stdc++.h>
#define int long long
#define MAXN 50005
#define endl '\n'
using namespace std;
int l,n,m,ans;
int a[MAXN];
bool cheak(int x){//目前查找的最小距离 
    int num=0,now=0;//要搬走的石头数,当前在的石头 
    for(int i=1;i<=n;i++){
        if(a[i]-now<x)num++;//如果比当前x小,那么这种距离下要搬走的石头个数+1 
        else now=a[i];//跳到后一块石头 
    }
    if(l-now<x)num++;//注意最后一块石头与总距离之间的距离也要小于x 
    return num<=m;//返回是否满足条件 
}
signed main(){
    cin>>l>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    int L=1,R=l;
    while(L<R){
        int mid=(L+R+1)>>1;
        if(cheak(mid))ans=L=mid;//往右查询是否有最大值 
        else R=mid-1;//当前移走石头数大于M,只能往左查询 
    }
    cout<<ans<<endl;
    return 0;
} 

posted @ 2024-03-18 20:14  iridescent94  阅读(42)  评论(0)    收藏  举报  来源