题目链接
/*思路:二分枚举
* 由于给定了起点(0)和终点(d)的确切位置(有界性)
* 并且石头按序排列(单调性)
* 而答案要求最小值最大(最大值最小也可以,这道题不是)
* 这就满足用二分搜索做题的条件
* 虽然直接求出正确答案很难,但可以用较低的复杂度枚举答案
* O(lg(n))的复杂度是完全可以接受的
*/
#include <bits/stdc++.h>
using namespace std;
#define N 50005
int a[N];
int d, m, n;
/*我们难以确认在哪个位置删除石头
* 但对于某个答案x
* 两块石头间的间距一定不小于x(x已经是最小间距了)
* 由此,遍历所有的石头可以确认需要删除哪些石头
* 如果删除的石头小于等于最大可删除石头数量
* 该答案就是合法的
*/
bool judge( int x )//判断答案是否合法
{
int flag = 0, i = 0, now = 0;
/*flag是对于x而言移除石头的数量
*i是下一块判断要跳或是删除的石头
* now是现在所处的石头
*/
while ( i < n + 1 )//遍历石头
{
i++;//向后枚举
if ( a[i] - a[now] < x )//如果这块石头到现在所处的石头距离小于x
flag++;//删了它,然后继续
else//否则就跳上去
now = i;
}
if ( flag > m )//删的太多了,不符合答案要求
return false;
else
return true;
}
int main( )
{
cin >> d >> n >> m;
a[0] = 0;//起点0
for ( int i = 1 ; i <= n ; i++ )
cin >> a[i];
a[n + 1] = d;//终点坐标
int l = 1, r = d, ans;//答案和答案区间
while ( l <= r )//二分枚举
{
int mid = (l + r) / 2;
if ( judge( mid ))//如果当前的mid是合法答案
{
ans = mid;//存起来
l = mid + 1;//向右枚举
/*为什么需要向右枚举?
* 因为虽然当前的答案是合法的
* 但不一定是最优的
* 但最优答案一定是合法的
* 所以要找出所有的答案
* 再取出最优解.
* 为什么不需要比较?
* 因为每次求得合法答案之后的向右枚举
* 区间开头已经是mid+1了
* 也就是之后的合法答案一定大于现在的答案
*/
}
else//不合法就向左枚举
r = mid - 1;
}
cout << ans;//输出最后的答案
return 0;
}