二分最短跳跃距离,贪心从左到右判定:与上一块保留岩石距离不足 x 就移走当前岩石,O(N log L)。
OJ: roj
题目 ID: 3631
难度:普及+/提高-
标签:
创建: 2026-10-02 11:31
更新: 2026-10-10 11:30
形式化题目
在数轴上,起点位于
样例:
正解
思路
朴素做法:枚举移走哪些岩石(组合数
第一步:把「最大化最小值」转化为判定问题。 直接求「最短跳跃距离的最大值」很难,但它具有单调性——如果我们问「最短跳跃距离能否达到
越大,要求越苛刻,可行方案越少; - 定义
= 使所有相邻距离 时至少要移走的岩石数,则 越大 越大。
所以存在一个临界值
第二步:贪心判定。 从左到右扫描(起点、岩石、终点统一看待),维护「上一块保留岩石的位置」
- 若当前位置
与 的距离 :移走当前岩石(计数 ), 不变; - 否则保留当前岩石,
。
为什么移走当前岩石而不是更左边的?当
终点不能移走怎么办? 把终点
用样例验证
| 扫描位置 | ||
|---|---|---|
| 结果 |
所以答案就是
flowchart LR
A[二分区间 lo=1, hi=L] --> B{mid = lo+hi+1 除以 2}
B --> C[贪心扫描: 距上一保留点小于 mid 则移走]
C --> D{移走块数 cnt 小于等于 M ?}
D -- 是 --> E[lo = mid]
D -- 否 --> F[hi = mid - 1]
E --> G{lo 等于 hi ?}
F --> G
G -- 否 --> B
G -- 是 --> H[输出 lo]
代码
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-10 11:30
* update_at: 2026-10-10 11:30
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){ios::sync_with_stdio(false);cin.tie(nullptr); int l,n,m; if(!(cin>>l>>n>>m)) return 0; vector<int> pos(n+1); for(int i=0;i<n;i++) cin>>pos[i]; pos[n]=l; int lo=1,hi=l; while(lo<hi){int mid=(lo+hi+1)/2; int cnt=0,prev=0; for(int i=0;i<=n;i++){ if(pos[i]-prev<mid) cnt++; else prev=pos[i]; } if(cnt<=m) lo=mid; else hi=mid-1;} cout<<lo<<'\n'; return 0;}"""跳石头:二分答案 + 贪心判定。O(N log L)"""
import sys
def main():
data = iter(map(int, sys.stdin.buffer.read().split()))
l, n, m = next(data), next(data), next(data) # 终点距离 / 岩石数 / 可移走数
d = [next(data) for _ in range(n)] # 岩石到起点距离,已升序
pos = d + [l] # 把终点也看作一块岩石
def check(x: int) -> bool:
cnt, prev = 0, 0 # prev = 上一块保留岩石的位置
for p in pos: # 依次考虑每块岩石(含第一块与终点)
if p - prev < x: # 距离不足,移走当前岩石
cnt += 1
else:
prev = p # 保留它
return cnt <= m # 终点不可移走,cnt 天然不含终点被移
lo, hi = 1, l # 答案在 [1, L]
while lo < hi:
mid = (lo + hi + 1) // 2
if check(mid):
lo = mid
else:
hi = mid - 1
print(lo)
main()复杂度
- 时间复杂度:
。二分 轮(约 轮),每轮贪心扫描 ,总计约 次操作。 - 空间复杂度:
存放岩石位置。
总结
- 「最大化最小值」类问题的标准套路:二分答案 + 贪心/搜索判定。判定函数必须单调(这里
随 单调不减)。 - 贪心判定口诀:从左往右扫,与上一块保留的岩石距离不足
就移走当前岩石——移走靠右的一块永远不会更差。 - 终点不可移走的约束不需要特判:把终点加入扫描序列后,不可行的
会天然使计数超标。 - 易错点:扫描必须从第一块岩石开始(包含所有
块),漏掉第一块会导致答案偏大。