当前位置: 首页 > news >正文

第2题 - 登山鞋(C++实现)

第2题 - 登山鞋(C++实现)

题目内容

小明正在玩一个游戏:
游戏中有一排山峰,他需要从左到右依次经过 $n$ 座山,其中第 $i$ 座山的高度为 $h_i$。

在游戏开始之前,小明需要装备一双 登山鞋。假设鞋子的 耐久度 为 $x$,那么对于任意相邻的两座山,如果高度差 $|h_{i+1}-h_i| > x$,小明就无法攀爬过去。

小明在游戏开始前,可以进行 $K$ 次操作,每次可以把任意一座山的高度改为任意非负整数。

问题:小明能够装备的登山鞋的 最低耐久度 可以是多少?


输入描述

  • 第一行:一个正整数 $T$,表示数据组数。

  • 对于每组数据:

    • 第一行输入两个正整数 $n, K$,表示山的数量和小明购买的操作次数。
    • 第二行输入 $n$ 个整数,表示每座山的高度。

输出描述

  • 对于每组数据,输出一个整数,表示小明经过若干次操作之后,可以装备的登山鞋的 最低耐久度

样例

输入

3
1 1
2
5 1
1 2 4 7 8
5 3
6 4 7 10 5

输出

0
2
1

样例解释

  • 第一组:只有一座山,不需要鞋子,答案是 0。
  • 第二组:可以把高度改为 [1,2,4,6,8],那么相邻高度差最大为 2。
  • 第三组:可以改为 [6,6,7,8,9],那么相邻高度差最大为 1。

算法思路

关键观察

  • 修改最多 $K$ 个位置,等价于 至少保留 $n-K$ 个位置 不变。
  • 被修改的位置可以随意设置,用来“补”出来满足条件。

因此问题转化为:
给定一个耐久度 $x$,能否保留至少 $n-K$ 个位置,使得相邻保留位置 $i,j$ 满足:

∣hj−hi∣≤(j−i)×x |h_j - h_i| \leq (j-i) \times x hjhi(ji)×x

这样就能通过“线性插值”把中间修改的山峰补出来。

判定函数(feasible)

  • 类似 最长上升子序列(LIS)的 DP 思路:

    • dp[i] 表示以第 $i$ 座山结尾的“可保留子序列”最大长度。
    • 转移条件:
      如果 $|h[i]-h[j]| \leq (i-j)\times x$,则 dp[i] = max(dp[i], dp[j]+1)
  • 如果最后的最大长度 ≥ $n-K$,说明耐久度 $x$ 可行。

时间复杂度:单次 DP 为 $O(n^2)$。

二分答案

  • 耐久度 $x$ 的最小值单调:

    • 如果 $x$ 可行,那么更大的 $x$ 也一定可行。
  • 用二分法找到最小的 $x$。

  • 上界 $R$ 可以取 相邻差的最大值(不修改的情况下必然可行)。

整体复杂度:

  • 二分次数 $O(\log R)$
  • 每次判定 $O(n^2)$
  • 总复杂度 $O(n^2 \log R)$

C++代码实现

#include <bits/stdc++.h>
using namespace std;// 判定函数:给定耐久度 x,是否能保留至少 n-K 个位置
bool feasible(const vector<int>& h, int n, int K, int x) {int need = n - K;               // 至少需要保留的数量vector<int> dp(n, 1);           // dp[i]:以 i 结尾的可保留子序列长度int best = 1;for (int i = 0; i < n; i++) {for (int j = 0; j < i; j++) {// 如果相邻两点满足 |h[i]-h[j]| <= (i-j)*xif (abs(h[i] - h[j]) <= x * (i - j)) {dp[i] = max(dp[i], dp[j] + 1);}}best = max(best, dp[i]);if (best >= need) return true; // 提前结束}return best >= need;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin >> T;while (T--) {int n, K;cin >> n >> K;vector<int> h(n);for (int i = 0; i < n; i++) cin >> h[i];// 边界情况:只有一座山if (n <= 1) {cout << 0 << "\n";continue;}// 计算最大相邻差,作为二分上界int R = 0;for (int i = 1; i < n; i++) {R = max(R, abs(h[i] - h[i - 1]));}int l = 0, r = R;while (l < r) {int mid = (l + r) / 2;if (feasible(h, n, K, mid)) r = mid;else l = mid + 1;}cout << l << "\n";}return 0;
}

示例运行

输入:

3
1 1
2
5 1
1 2 4 7 8
5 3
6 4 7 10 5

输出:

0
2
1

与题目样例完全一致。


总结

这道题的关键在于:

  1. 把“修改 K 个位置”转化为“保留 n-K 个位置”。
  2. 利用 DP + 二分的方法,判定某个耐久度是否可行。
  3. 通过二分搜索找到最小的耐久度。

该方法时间复杂度约为 $O(n^2 \log R)$,在数据规模中是可行的。


http://www.dtcms.com/a/347844.html

相关文章:

  • 计算机组成原理(12) 第二章 - 主存储器的基本组成
  • 遥感机器学习入门实战教程|Sklearn案例⑨:数据预处理(Processing)
  • 基于STM32的智能温室控制系统设计
  • 【yocto】Yocto Project 配置层(.conf)文件语法详解
  • Service详解
  • 鸿蒙异步处理从入门到实战:Promise、async/await、并发池、超时重试全套攻略
  • 【C++】全局变量/静态变量的初始化时机
  • 基于电力电子变压器的高压脉冲电源方案复现
  • 最小覆盖子串+滑动窗口
  • 【JVM内存结构系列】二、线程私有区域详解:程序计数器、虚拟机栈、本地方法栈——搞懂栈溢出与线程隔离
  • mysql为什么使用b+树不使用红黑树
  • tcpdump命令打印抓包信息
  • 用vscode使用git工具
  • 深度优先搜索(DFS)和广度优先搜索(BFS)
  • 【内网渗透】Relay2LDAP之NTLMKerberos两种利用
  • windows中bat脚本的一些操作(三)
  • 如和在不同目录之间引用模块-python
  • 微调系列:LoRA原理
  • MVC模式在个人博客系统中的应用
  • 【通俗易懂】TypeScript 增加了 JavaScript 的可选链 (?.) 和空值合并运算符 (??)理解
  • 【集合和映射】USACO Bronze 2019 December - 我在哪Where Am I?
  • 机器学习案例——预测矿物类型(模型训练)
  • DS18B20温度传感器详解
  • 电阻的功率
  • 多光谱相机检测石油石化行业的跑冒滴漏的可行性分析
  • 电蚊拍的原理及电压电容参数深度解析:从高频振荡到倍压整流的完整技术剖析
  • 决策树基础学习教育第二课:量化最优分裂——信息熵与基尼系数
  • 01_Python的in运算符判断列表等是否包含特定元素
  • [Vid-LLM] 创建和训练Vid-LLMs的各种方法体系
  • crypto.randomUUID is not a function