2188. 完成比赛的最少时间
考点
- 线性DP
- 贪心
- 完全背包
思路
一、问题抽象与核心难点
题目给定若干种轮胎,每种轮胎由两个参数描述:
- \(f\):该轮胎在新胎状态下跑第一圈的时间
- \(r\):每多跑一圈,单圈时间乘以的增长系数
若连续使用同一条轮胎跑圈,其第 \(k\)
圈耗时为: \[
f \cdot r^{k-1}
\] 允许在任意两圈之间换胎,换胎需要固定时间
changeTime,且换胎后轮胎状态重置为新胎。
目标是:恰好跑完 numLaps
圈,使总时间最小。
1. 直接建模的失败尝试
一种直观但不可行的建模方式是: \[ dp[i][j][k] = \text{前 } i \text{ 圈,用第 } j \text{ 种轮胎,当前胎已连续跑 } k \text{ 圈的最小时间} \] 该状态维度过高,时间与空间复杂度均不可接受。
2. 关键建模思想:分段 + 状态压缩
比赛过程中,轮胎的历史使用情况不重要。 每次换胎,都相当于拿到一条“全新轮胎”,其第一圈耗时一定是 \(f\)。
因此,整个比赛可以被视为:
将
numLaps圈划分为若干连续区间(段), 每一段使用一条新轮胎连续跑若干圈。
二、子问题一:连续使用一条新胎跑 \(k\) 圈的最小时间
1. 子问题定义
定义数组: \[ \text{best}[k] = \min \left\{ \text{任意一种轮胎,连续使用 } k \text{ 圈的总时间} \right\} \] 对于某一轮胎 \((f, r)\),连续跑 \(k\) 圈的耗时为: \[ f + fr + fr^2 + \cdots + fr^{k-1} \]
2. 有效枚举上界(剪枝理由)
随着 \(k\) 增大,单圈时间呈指数增长。 当出现: \[ f \cdot r^{k-1} > f + \text{changeTime} \] 说明:
- 再跑这一圈,不如 换胎 + 跑新胎第一圈
- 因此继续扩展该轮胎的连续圈数不可能出现在最优解中
由此,每条轮胎的有效连续圈数非常有限(通常几十以内)。
3. 预处理策略
对每一种轮胎:
- 从 \(k = 1\) 开始逐圈累加耗时
- 一旦单圈时间超过 \(f + \text{changeTime}\),立即停止
- 用当前轮胎的连续耗时更新
best[k]
该步骤时间复杂度为: \[
O(\text{轮胎数} \times K)
\] 其中 \(K\)
为连续圈数的自然上界,远小于 numLaps。
三、子问题二:分段动态规划
1. DP 状态定义
定义一维 DP: \[ dp[i] = \text{恰好跑完 } i \text{ 圈的最小总时间} \]
2. 状态转移方程
假设最后一段连续跑了 \(k\) 圈,则: \[ dp[i] = \min_{1 \le k \le i} \left( dp[i-k] + \text{best}[k] + \text{changeTime} \right) \] 解释:
best[k]:该段内连续跑 \(k\) 圈的最小耗时changeTime:进入这一段前的换胎成本
3. 第一段的特殊处理
第一段不需要换胎。 实现上统一加上
changeTime,在最终答案中减去一次即可: \[
\text{answer} = dp[\text{numLaps}] - \text{changeTime}
\]
4. 复杂度分析
- DP 状态数:\(O(\text{numLaps})\)
- 每个状态最多枚举 \(K\) 种段长
总时间复杂度: \[ O(\text{numLaps} \times K) \]
四、完整算法流程总结
- 预处理
best[k]- 枚举每种轮胎
- 计算其可行的连续圈数及对应耗时
- 更新全局最优
- 一维分段 DP
- 使用
best进行区间划分转移 - 统一加换胎时间,最后减一次
- 使用
五、AC代码
1 | class Solution { |
六、建模思想一句话总结
本题的核心不是“轮胎跑到第几圈”, 而是“每次换胎后,连续跑多少圈最划算”。
通过将“轮胎选择 + 使用历史”压缩为“连续段长度”, 原本高维状态被成功降为 一维分段动态规划。