跳跃型 DP (线性 DP 进阶)
算法简介
跳跃型 DP 指的是状态转移不再是简单的从 $i-1$ 到 $i$ ,而是从满足特定条件的前驱位置 $j$ 转移到$i$的一类问题。核心难点在于如何快速找到最优的$j$,从而避免$O(N^2)$的暴力枚举。
- 核心特征:$dp[i] = \max/ \min \{ dp[j] \} + \text{cost}$,其中$j i$且满足特定限制(如数值大小、距离范围、属性匹配等)。
- 时间复杂度:朴素做法为$O(N^2)$,通过优化查找可降至$O(N \log N)$或$O(N)$。
- 基本枚举顺序:通常为线性枚举$i$,但在计算$dp[i]$时需要高效查找$j$。
- 状态转移:
- 经典场景: - 最长上升子序列 (LIS)
- DP 状态定义 当正向依赖关系复杂时,尝试定义$dp[i]$为“从$i$开始到结尾”的最优解(如《尼克的任务》)。
- 多维状态 当简单的$dp[i]$无法区分不同情况时,增加维度。例如$dp[i][\text{diff}]$表示以$i$结尾且公差为$\text{diff}$的链长。
------
一、朴素限制模型 ($O(N^2)$)
1. 核心原理
这是跳跃型 DP 的基础。题目规定了明确的转移条件(如 LIS 中的$a[j] a[i]$),但数据范围允许$O(N^2)$。侧重于理解状态定义和合法性判断。
$$dp[i] = \max_{\substack{0 \le j i \\ \text{check}(j, i) \text{ is true}}} \{ dp[j] \} + 1$$
- 合唱队形 (双向 LIS)
- 满足特定公差/条件的子序列
2. 常用技巧
3. 代码模板
// 朴素 LIS 模板
for (int i = 1; i <= n; i++) {
dp[i] = 1; // 初始化:自身构成长度为 1 的序列
for (int j = 1; j < i; j++) {
// 核心:检查跳跃条件
if (a[j] < a[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
ans = max(ans, dp[i]);
}二、特殊查找与性质优化模型
1. 核心原理
当$N$达到 $10^5$ 时,不能遍历 $j$。我们需要利用题目性质(如数值单调性、二进制位、因数等),将查找前驱的复杂度从$O(N)$降为$O(\log N)$或$O(1)$。
2. 常用技巧
q,其中q[len]存储长度为len的子序列中结尾最小的数值。利用std::lower_bound快速查找。max_val[30],记录第$k$位为 1 的最大 dp 值。vector<int> end_at[i]预处理所有以$i$结尾的区间,DP 时直接遍历 vector。三、单调队列优化模型
1. 核心原理
这类问题通常要求“跳跃距离”在一定范围内,即$L \le i - j \le R$。这构成了典型的滑动窗口最值问题。
$$dp[i] = \max_{i-R \le j \le i-L} \{ dp[j] \} + \text{cost}[i]$$
std::deque) 维护候选集合。队列中存储下标,且对应的$dp$值是单调递减的。2. 常用技巧
q.front() < i - R时,说明队首元素已经超出了最大跳跃距离,必须扔掉。check。- 查询:查询区间 $[1, a[i]-1]$ 内的 $dp$ 最大值作为最优前驱。
- 更新:计算完 $dp[i]$ 后,将位置 $a[i]$ 的值更新为 $dp[i]$。
- 注意:若数值很大(如 $10^9$),需要先进行离散化。
3. 代码模板
// 单调队列优化 DP 模板
deque<int> q;
for (int i = 1; i <= n; i++) {
// 1. 尝试将 i-L 加入候选队列 (注意边界)
int pre = i - L;
if (pre >= 0) {
// 维护单调性:如果新来的比队尾优,队尾就没用了
while (!q.empty() && dp[q.back()] <= dp[pre]) q.pop_back();
q.push_back(pre);
}
// 2. 移除过期的候选 (距离超过 R)
while (!q.empty() && q.front() < i - R) q.pop_front();
// 3. 取队首作为最优决策进行转移
if (!q.empty()) {
dp[i] = dp[q.front()] + cost[i];
}
}【前置衔接知识点】
1、动态规划基础
【思维导图】

【题目知识点分类】
01
最长上升子序列
普及/提高-
--
练习
02
合唱队形
普及/提高-
--
练习
03
尼克的任务
普及/提高-
--
练习
04
得到山形数组的最少删除次数
普及/提高-
--
练习
05
最佳球队组建
普及/提高-
--
练习
06
神秘的礼物
普及/提高-
--
练习
07
大师
普及+/提高
--
练习
08
挖地雷
普及/提高-
--
练习
09
淘金者
普及/提高-
--
练习
10
绝世好题
普及+/提高
--
练习
11
Good Sequences
普及+/提高
--
练习
12
[NOIP 1999 提高组] 导弹拦截
普及+/提高
--
练习
13
饥饿的奶牛
普及+/提高
--
练习
14
连锁反应
普及/提高-
--
练习
15
琪露诺
普及+/提高
--
练习
16
鲁道夫与 k 座桥
普及+/提高
--
练习
17
[POI 2014] PTA-Little Bird
提高+/省选-
--
练习
18
[NOIP 2017 普及组] 跳房子
提高+/省选-
--
练习
19
[HNOI2004] 打鼹鼠
普及/提高-
--
练习
20
[CSP-J 2022] 上升点列
普及/提高-
--
练习