题目:问一个青蛙在河边,来回走2x次,在有石头可借助的情况下,最小的跳跃距离
思路1(自己想的):
二分跳跃能力 y [1, 1e5]
检验该跳跃能力是否能够让青蛙在2x次过河中顺利到达
每次跳跃贪心策略,跳到青蛙 在y范围内最远的一块石头
要遍历2x次
问题:该思想使用二分y没问题,问题就在check函数怎么写,使用贪心策略,不一定就是正确解,并且check函数要写x次遍历,每次遍历还要来回往返两次遍历。这种思想还没写出来,有待验证
思路2(B站讲解+题解):
二分跳跃能力,取右区间左端点。
问题还在于check函数怎么写,对题目的意思进行仔细的分析与不断的化简:
1) 青蛙往返一次,相当于青蛙从河边到对岸两次,两者是对等的。因此化简为单向的问题
2) 青蛙经过河第一次时,可能落在[1, y], [2, y+1],[3, y+2]...
而青蛙经过2x次,因此只要在各个区间内石头的高度>=2x即可成立
思路2代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, x;
int h[N], s[N];
bool check(int y)
{
//判断[1,y], [2, y] ... 每个区间是否有>=2x个石头的高度
for (int i = 1; i + y <= n; i ++)
{
long long res = s[i + y - 1] - s[i - 1];
if (res < 2 * x) return false;
}
return true;
}
int main()
{
scanf("%d%d", &n, &x);
for (int i = 1; i <= n; i ++)
{
scanf("%d", &h[i]);
s[i] = s[i - 1] + h[i];
}
int l = 1, r = 1e5;
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
// cout << mid << " ";
}
cout << l << endl;
return 0;
}