二分真的好难/(ㄒoㄒ)/~~!
首先看题,题目中我们可以知道选手跳跃最短距离的最大值,所以我们可以使用二分。
判断是否需要二分可以看题目中是否有类似求最短距离的最大值或者最大距离的最小值。
那么本题怎么进行二分呢
我们可以以整段距离为一个大区间,然后二分取其中间值,用其中间值来暂时当作一个最大的最小跳跃距离,以此来求需要搬掉几块石头。如果石头搬多了那么说明我们选择的值太大,搬少了,说明我们选择的值太小。最后两个端点就可以确定同一个值了。
废话不多说,上代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 5 * 1e4 + 10;
//typedef long long LL;
int l, n, m, ans;
int d[N];
//二分模板一般时比较固定的,但是难就难在中间的check函数上
inline int read()//快读不解释
{
int sum = 0;
char ch = getchar();
while (ch > '9' || ch < '0')
ch = getchar();
while (ch <= '9' && ch >= '0')
sum = sum * 10 + ch - 48, ch = getchar();
return sum;
}
bool check(int x)//x为中间值
{
int cnt = 0;//判断移去的石头的数量
int next = 0;//下一块石头的位置
int now = 0;//运动员所处的位置
while (next < n + 1)
{
next++;
if (d[next] - d[now] < x)//如果两块石头的位置小于我们需要的x,则可以搬掉next所在的这个石头,运动员位置保持不变来判断下一块。
{
cnt++;//搬掉了一块石头
}
else
now = next;//中间距离超过了我们现在的最大的最小距离,则不能搬,运动员到这个石头的位置
}
if (cnt > m)//看看搬的石头是多还是少
return false;
else
return true;
}
int main()
{
l = read(), n = read(), m = read();
for (int i = 1; i <= n; ++i)
{
d[i] = read();
}
d[n + 1] = l;
int rl = 1, r = l;//rl为左端点,r为右端点
while (rl <= r)//二分模板
{
int mid = (rl + r) / 2;
if (check(mid))//值太小,搬少了或者搬得刚刚好
{
ans = mid;//暂时存到这里,看看有没有更好的解
rl = mid + 1;
}
else//值太大,搬少了
r = mid - 1;
}
cout << ans << endl;//最后的答案
return 0;
}