洛谷P10909题(2024年蓝桥杯国B):用二分查找+动态规划解决立定跳远问题

一、题目解读
洛谷P10909题是一个关于跳跃游戏的算法问题,要求玩家在给定限制条件下找到最小的跳跃能力值L。题目核心在于如何高效判断某个L值是否满足要求,并利用二分查找优化搜索过程。难点在于处理"爆发技能"这一特殊机制,该技能允许玩家在特定情况下将跳跃距离临时翻倍。
二、解题思路
二分查找框架:通过二分法在可能的最小和最大L值之间搜索最优解
验证函数check():核心验证逻辑分为两种情况:
不使用爆发技能时的常规跳跃判断
使用爆发技能时的特殊处理(可跳过2L距离)
边界处理:特别处理n=1的特殊情况,以及爆发技能在序列末尾的使用机会
三、解题步骤
读取输入数据并处理n=1的特殊情况
初始化二分查找的左右边界(left=1, right=最大距离)
在每次二分迭代中:
计算中间值mid
分别验证使用/不使用爆发技能的情况
根据验证结果调整搜索边界
输出最终找到的最小L值
四、完整代码与注释
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool check(long long L, const vector<int>& a, int m, bool use_boost) {
int cnt = 0;
long long prev = 0;
bool boost_used = false;
for (int i = 0; i < a.size(); ++i) {
long long dist = a[i] - prev;
if (use_boost && !boost_used && dist > L) {
// 尝试在此处使用爆发技能
if (dist <= 2 * L) {
boost_used = true;
prev = a[i];
continue;
}
}
if (dist > L) {
cnt += (dist - 1) / L;
if (cnt > m) return false;
}
prev = a[i];
}
// 如果使用爆发技能但没用上,尝试在最后使用
if (use_boost && !boost_used) {
long long last_dist = a.back() - (a.size() > 1 ? a[a.size()-2] : 0);
if (last_dist > L && last_dist <= 2 * L) {
boost_used = true;
}
}
return cnt <= m && (!use_boost || boost_used);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<int> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
// 处理特殊情况:n=1时只需要跳一次
if (n == 1) {
cout << (a[0] + 1) / 2 << endl;
return 0;
}
long long left = 1, right = a.back(), ans = a.back();
while (left <= right) {
long long mid = (left + right) / 2;
if (check(mid, a, m, false) || check(mid, a, m, true)) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
cout << ans << endl;
return 0;
}五、总结
本解法通过二分查找将时间复杂度优化至O(n log D),其中D是最大距离。爆发技能的智能使用策略是本算法的亮点,通过在check函数中动态判断最佳使用时机,既保证了正确性又提高了效率。这种思路可以推广到其他带有特殊技能机制的算法问题中。
原创内容 转载请注明出处
