洛谷P2678 跳石头 二分
[题目传送门][https://www.luogu.com.cn/problem/P2678]
题意:笔直的河道中有N块岩石,起点到终点的距离为L,要移走M块,求两两石头间隔最短距离的最大值。
思路:
以最短距离为左端点,以L为右端点进行二分,以每次的MID为最短距离求取需要移走的岩石数K,
若K>m,说明间隔太大,需要移走的岩石数过多,令R=MID-1,向左进行二分;
若K<m,说明间隔太小,需要移走的岩石数过少,K=m时,需要移走的岩石数刚好=m,因为要求取最大值,都应向更大的间距进行尝试,令L(左端点)=MID+1,向右进行二分。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const double PI = 3.141592;
const int e = 5e5;
int l, n, m;
ll ans, minx;
ll a[e + 5], b[e + 5];
bool jud(ll x){ //获得以mid为最短跳跃距离的最大值,求的需要移走的岩石数
ll res = 0, num = 0;
for(int i = 1; i <= (n + 1); i++){
if(res + b[i] < x){
res += b[i];
num += 1;
}
else{
res = 0;
}
}
//若移走岩石数<=m,继续向大的数进行尝试
if(num <= m) return 1;
else return 0;
}
int main()
{
scanf("%d %d %d", &l, &n, &m);
a[0] = 0;
minx = a[1] - a[0]; //求间距最小值,不能设为INF,防止m=0,n=0时WA
for(int i = 1; i <= n; i++){
scanf("%lld", &a[i]);
//b数组来储存相邻两石头间距,共n+1项
b[i] = a[i] - a[i - 1];
if(b[i] < minx) minx = b[i];
}
b[n + 1] = l - a[n];
ll L = minx, R = l;
while(L <= R){
ll mid = (L + R) / 2;
if(jud(mid)){
ans = mid;
L = mid + 1;
}
else R = mid - 1;
}
printf("%d\n", ans);
return 0;
}
类似的题目:[洛谷 P1182 数列分段 Section II][https://blog.csdn.net/weixin_43763903/article/details/105275933]