刚看到这个题时,相信有很多小伙伴和本蒟蒻一样——循环找出最小值,然后不断丢掉两端距离相对较小的石头,最后石头剩下N-M个时,直接输出最小间距。但是如此暴力的做法,终究会迎来残酷的结局——TLE*n……然后打开题目标签一看“贪心”“二分”,其中贪心很好理解嘛,尽量把小的间距全部去掉,留下的自然就大了;至于二分,本蒟蒻是个笨蛋,理解了好久才明白如何利用二分解答此类问题。
二分的大前提是找到左边界(min)和右边界(max),在这个题里,很明显你可以直接min=1,max=L来操作,实际上也确实能够AC,但是稍微思考一下,就会发现max其实并不是每次都能取到L,而是max=L/(N-M+1)。因为河里面至少有N-M块石头,那么就有N-M+1个间距,要取最大间距只能是石头按某一间隔均匀放置,所以就得到了max=L/(N-M+1)。
找完边界了,接着来判断二分的条件。这里我写了一个check函数,判断最小间距取mid是否合适。如果check(mid)==1,那么就说明这个mid满足条件,我们可以用ans记录该值,然后往mid+1-max这个区间继续找更符合(更大)的值;如果check(mid)==0,则说明mid不满足条件,得在min-mid-1中继续寻找合适的答案。最后当max<min时退出循环,输出ans即可。
本蒟蒻AC代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5;
int m, n, l, a[N], t[N];
bool check(int x)
{
int num{}, p{};
for (int i = 1; i <= n + 1; i++)//复制a数组给t,因为t每check一次都会改变
{
t[i] = a[i];
}
for (int i = 1; i <= n + 1; i++)
{
if (t[i] - t[i - 1] < x)
{
t[i] = t[i - 1];
num++;
}
}
return num <= m;
}
int main(void)
{
cin >> l >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
a[n + 1] = l;
int max{l / (n - m + 1)}, min{1}, mid{}, ans;
while (max >= min)//二分寻找最优答案
{
mid = max + min >> 1;
if (check(mid))
{
ans = mid;
min = mid + 1;
}
else
{
max = mid - 1;
}
}
cout << ans;
return 0;
}