P2678 [NOIP2015 提高组] 跳石头 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这道题运用了贪心+二分(贪心做题时候更多凭借感觉,证明很难而且时间成本高,更多靠题感)
难点是我们应该拿什么进行二分
经过多次尝试和参考积累的经验,我们不难想到要将结果进行二分(这道题弄懂之后就会想到了)
若最大的最短跳跃距离为x, 那么我们就需要把石头之间距离小于x的石头移走
统计移走石头的个数进行判断,进而就知道应该往左还是往右二分,套用二分模板即可
这里还有一个核心巧妙的点是before变量的使用,可以从代码中体会
#include <iostream>
#include <algorithm>
using namespace std;
int a[50010];
int s, n, m;
int main()
{
cin >> s >> n >> m;
for (int i = 0; i < n; i++) cin >> a[i];
//把可能的答案进行二分
int l = 1, r = s, mid, i;
while (l < r)
{
mid = l + r + 1 >> 1; //下面有l=mid 避免死循环这里要+1
int cnt = 0, before = 0; //cnt记录移走了多少石头, before记录上一个石头到起点的距离
for (i = 0; i < n; i++) //枚举每个石头
{
if (mid + a[i] > s) break; //如果再跳mid距离就超过总距离 那么直接break (主要判断最后一个石子到终点的距离)
if (a[i] - before < mid) cnt++; //两石头的距离小于mid 则移走
else before = a[i]; //否则记录before
}
cnt += n - i;//如果break了 就把i后面的是石头全部移走
if (cnt <= m) l = mid;
else r = mid - 1; //二分模板
}
cout << l;
return 0;
}
类似做法的题目 洛谷P3853 [TJOI2007]路标设置 、 洛谷P1182 数列分段 Section II