各位小伙伴们,如果有幸可以被你看到我的文章,是我的荣幸。近期我的小目标是争取一天分享一道题题解,当然可能有时候比较忙啦,尽量吧。题目的思路都是个人看法,不喜勿闷喔。新的一年希望大家都能找到好工作,过上自己满意的生活,希望我今年也能顺利找到好的实习、好的工作啦。废话不多说,上题目。
突然觉得做专项练习挺好的,这个题目一看就是用二分答案求解,时间复杂度比较低。 这道题需要找到最大的最短跳跃距离,使得最多移走M块岩石之后,每一步的跳跃距离都不小于这个最短跳跃距离。具备单调性,满足二分答案的要求。(若对二分答案不熟悉的小伙伴,指路我的第一篇关于二分答案的内容二分答案刷题1-CSDN博客)
1、 确定判断条件check函数。判断当前岩石和上一个岩石的距离是否小于minDist,小于则移除当前岩石(注:这里的判断,需要把终点加入,因为N只包括非终点的跳跃距离,但到终点还有一段距离)
mid
,使用 check
函数来验证是否可以通过移除至多 M
块岩石来满足这个跳跃距离。mid
的条件下需要移除的岩石数量。如果当前岩石与上一个岩石的距离小于 mid
,则计划移除这块岩石,并增加 remove
计数器。M
,则说明假设的跳跃距离是可行的;否则,不可行。2、 用二分查找缩短查找时间,每次用mid作为最短跳跃距离,直到找到为止,返回ans。
check(mid)
返回 true
,说明至少有一种方法可以在移除至多 M
块岩石的情况下,使每一步的跳跃距离都至少为 mid
。因此,更新答案 ans
为 mid
,并尝试更大的跳跃距离(增加 low
)。check(mid)
返回 false
,说明没有办法在移走至多 M
块岩石的情况下保持每一步的跳跃距离至少为 mid
。因此,减少跳跃距离(减小 high
)以寻找可能的更小跳跃距离。#include
using namespace std;
#define maxn 50010
int a[maxn];
int N, M;
long long L;
bool check(int minDist)
{
int remove = 0, last = 0; //初始移动岩石块和上一个岩石
for (int i = 1; i <= N+1; i++) //从1开始,因为0是起点,到N+1是因为包括终点
{
if (a[i] - last < minDist)
{
remove++;// 如果当前岩石和上一个岩石的距离小于minDist,则移除当前岩石
}
else
{
last = a[i]; // 否则,跳到当前岩石
}
}
return remove <= M; // 检查移除的岩石数量是否不超过M
}
int main()
{
cin >> L >> N >> M;
a[0] = 0; // 起点
for (int i = 1; i <= N; i++)
{
cin >> a[i];
}
a[N + 1] = L;//终点
int low = 0, high = L, mid, ans = 0;
while (low <= high)
{
mid = low + (high - low) / 2;
if (check(mid))
{
ans = mid;// 如果可以实现这个距离,则尝试更大的距离
low = mid + 1;
}
else {
high = mid - 1;// 如果不可以,则尝试更小的距离
}
}
cout << ans << endl;
return 0;
}