DP 三要素是?
考点:DP 三要素回顾(A1)。
解析:状态、转移、初值——状态定维度、转移定递推、初值定起点。✅ 正确
排除法:B/C/D 都不是 DP 的骨架。
关联 · A4/A5:状态与转移的细化。
判断题:DP 要求问题具有最优子结构——大问题的最优解包含子问题的最优解。
考点:最优子结构(A2)。
解析:DP 要求最优子结构——大问题的最优解包含子问题的最优解。✅ 正确
排除法:无(判断题)。混淆点:贪心也要最优子结构,区别在决策是否可回溯。
关联 · A3 无后效性:两大前提。
判断题:无后效性不是 DP 的前提——有后效性的问题也能直接递推求解。
考点:无后效性(A3)。
解析:无后效性是 DP 的前提——状态一旦确定,之后的决策不受"如何到达此状态"影响。"不是前提"的说法是错的。✅ 答案 B(错误)
排除法:无(判断题)。混淆点:有后效性要加状态维度消除(如记录上一步)。
关联 · A2 最优子结构:两前提缺一不可。
状态设计的原则是?
考点:状态设计(A4)。
解析:用最少的维度完整刻画当前局面——能区分不同决策的所有信息。✅ 正确
排除法:B 维度多浪费时空;C 信息不足;D 无原则。
关联 · F1 状压状态:集合压成一维的例子。
转移设计的原则是?
考点:转移设计(A5)。
解析:枚举当前状态的所有决策,转移到后继(或由前驱汇集)——保证不重不漏。✅ 正确
排除法:B/C/D 无依据。
关联 · B2 LIS 转移:经典转移实例。
DP 进阶总表是?
考点:进阶总表(A6)。
解析:线性(LIS/LCS/子段和)、背包(01/完全/多重/分组/依赖)、区间、树形、状压、数位。✅ 正确
排除法:B/C/D 以偏概全。
关联 · 本章各板块:总表即目录。
最长上升子序列(LIS)的定义是?
考点:LIS 定义(B1)。
解析:LIS = 原序列中严格递增、按下标顺序选取的最长子序列(可不连续)。✅ 正确
排除法:B 是连续递增子段(那是子串);C 重排破坏下标序;D 是子串。
关联 · B4 二分优化:子序列性允许跳过元素。
LIS 的 转移是?
考点:LIS 转移(B2)。
解析:( 且 ),答案取 。✅ 正确
排除法:B 只接前一元素(丢了 条件);C/D 无依据。
关联 · I 组代码:dp 数组实测 1 1 2 1 3 4 2 4。
判断题: 的 LIS 逐个枚举每个 前面的 —— 时约 次,必须优化。
考点:LIS O(n²)(B3)。
解析: 枚举每个 前面的 —— 时约 次,必须优化。✅ 正确
排除法:无(判断题)。混淆点: 远超 1 秒极限。
关联 · B4 二分优化:优化的动机。
判断题:LIS 二分优化()维护一个"最小结尾数组"tail,用 lower_bound 找到第一个 的位置替换——tail 的长度即答案。
考点:二分优化(B4)。
解析:维护"最小结尾数组"tail,用 lower_bound 找第一个 的位置替换——tail 长度即答案,。✅ 正确
排除法:无(判断题)。混淆点:tail 内容不是真实 LIS(I4 实测 1 2 5 6)。
关联 · I3/I4 代码:长度 4、tail 1 2 5 6。
判断题:LIS 变体——最长不下降子序列(用 upper_bound)、先离散化、配合树状数组求方案数——核心思想都是"最小结尾"。
考点:LIS 变体(B5)。
解析:最长不下降用 upper_bound、离散化后树状数组求方案数——核心都是"最小结尾"。✅ 正确
排除法:无(判断题)。混淆点:不下降允许相等 → 换 upper_bound。
关联 · B4:同一思想换边界。
LCS(最长公共子序列)的转移是?
考点:LCS(B6)。
解析: 时 ;否则 。✅ 正确
排除法:B/C 无条件 +1;D 无依据。
关联 · B1 子序列:LCS 也是子序列类。
判断题:最大子段和——,答案取 ;全负数组答案为最大单元素。
考点:最大子段和(B7)。
解析:,答案取 max;全负数组答案为最大单元素。✅ 正确
排除法:无(判断题)。混淆点:经典例子 {-2,1,-3,4,-1,2,1,-5,4} → 6。
关联 · A5 转移:一维转移教科书。
01 背包(每件物品选 0/1 次)的转移是?
考点:01 背包回顾(C1)。
解析:,容量从大到小枚举——保证每件只用一次。✅ 正确
排除法:B 正序会重复使用(P1 实测 6);C/D 无依据。
关联 · J 组代码:W=7 输出 9。
完全背包(每件物品无限次)与 01 背包的区别是?
考点:完全背包(C2)。
解析:容量从小到大枚举——允许同一物品被反复使用。✅ 正确
排除法:B 逆序变 01;C 说反;D 错。
关联 · P3 易错:完全写逆序只出 3。
判断题:多重背包(每件物品有 件)用二进制拆分——把 拆成 件打包,转成 01 背包,复杂度从 降到 。
考点:多重二进制拆分(C3)。
解析:把 件拆成 打包转 01——复杂度 。✅ 正确
排除法:无(判断题)。混淆点:拆分后每包"选或不选"恰能组合出 0..c 任意件数。
关联 · J4 代码:4 件拆成 1+2+1 三包。
判断题:分组背包——每组最多选一件,转移时对每件物品做 01 式决策,容量循环仍在外层。
考点:分组背包(C4)。
解析:每组最多选一件——组内逐件做 01 式决策,容量循环在外层。✅ 正确
排除法:无(判断题)。混淆点:顺序 = 先容量后组内物品。
关联 · C5 依赖背包:依赖是分组的推广。
判断题:依赖背包(选子件必须先选主件)——先处理主件分组,组内做类似 01/分组决策。
考点:依赖背包(C5)。
解析:选子件必须先选主件——主件分组后组内做 01/分组决策。✅ 正确
排除法:无(判断题)。混淆点:L4 实测链 1-2-3 选 2 个得 3。
关联 · L4 树上背包代码:树上的依赖背包。
判断题:混合背包——把 01 与完全分两类处理(01 逆序、完全正序),循环方向对就不会错。
考点:混合背包(C6)。
解析:01 逆序、完全正序分两类处理——循环方向对就不会错。✅ 正确
排除法:无(判断题)。混淆点:J6 实测 01(2,3)+完全(3,4) W=6 得 8。
关联 · J6/N6 代码:混合实测。
判断题:背包用一维数组就是"滚动数组"思想——只保留上一阶段结果,空间 ;二维压缩一维时注意循环方向。
考点:滚动数组(C7)。
解析:一维背包就是滚动数组——只保留上一阶段,空间 ;压缩时注意方向。✅ 正确
排除法:无(判断题)。混淆点:O7 的 i&1 是通用版。
关联 · G1/O7:同一思想。
区间 DP 的核心思想是?
考点:区间 DP 思想(D1)。
解析:先算短区间再算长区间—— 由内部更小区间合并而来。✅ 正确
排除法:B/C/D 不是区间 DP。
关联 · D4 长度枚举:实现该思想的顺序。
石子合并(相邻合并、代价为两堆和)的转移是?
考点:石子合并(D2)。
解析:,枚举分割点 。✅ 正确
排除法:B/C/D 无依据。
关联 · K1 代码:{4,5,3} → 20。
判断题:环形问题(环形石子合并)→ 断环成链:数组复制一倍( 接 ),枚举所有长度为 的窗口取最优。
考点:环形断环成链(D3)。
解析:复制一倍 接 ,枚举所有长度为 的窗口取最优。✅ 正确
排除法:无(判断题)。混淆点:K3 实测 {4,5,3} 环形得 19。
关联 · K3 代码:断环成链实例。
判断题:区间 DP 必须按区间长度从小到大枚举(外层 len)——保证用到的子区间都已算好。
考点:长度枚举顺序(D4)。
解析:按区间长度从小到大枚举(外层 len)——保证用到的子区间都已算好。✅ 正确
排除法:无(判断题)。混淆点:P2 实证顺序错得 21。
关联 · P2 易错:顺序错 = 用未算的 INF。
判断题:括号序列类区间 DP—— 表示区间内最少添加/匹配数,枚举分割点或首尾配对。
考点:括号匹配(D5)。
解析: 表示区间内最少添加/匹配数,枚举分割点或首尾配对。✅ 正确
排除法:无(判断题)。混淆点:与石子合并同骨架,代价函数不同。
关联 · D6 回文:同骨架另一实例。
判断题:最长回文子序列(区间 DP)——首尾相等则 ,否则取两端子区间的 max。
考点:回文子序列(D6)。
解析:首尾相等 ,否则取两端子区间 max。✅ 正确
排除法:无(判断题)。混淆点:K4 实测 {1,2,2,1,3} 得 4。
关联 · K4 代码:回文实测。
判断题:四边形不等式优化适用于所有区间 DP,任何 区间 DP 都能优化到 。
考点:四边形不等式思想(D7)。
解析:四边形不等式优化不是万能——要求转移代价满足特定单调性(如石子合并的 w 满足),不是所有区间 DP 都能 。✅ 答案 B(错误)
排除法:无(判断题)。混淆点:优化有条件,S 组了解思想即可。
关联 · D2 石子合并:石子合并正是可优化的例子。
树上 DP 的核心做法是?
考点:树上 DP 思想(E1)。
解析:后序遍历(DFS 返回后合并子树信息)——先算儿子再算父亲。✅ 正确
排除法:B/C/D 会用到未算的儿子。
关联 · L 组代码:直径/独立集全是后序。
树的直径(最长两点路径)的 DP 求法是?
考点:树的直径(E2)。
解析:每个点维护子树最长链 与次长链 (不同子树),。✅ 正确
排除法:B 直径不是最长边;C/D 错。
关联 · L1 代码:6 点树直径 4。
判断题:树的重心 = 删去后最大连通块最小的点——DP 求每个点子树大小 ,再与 取 max 比较。
考点:树的重心(E3)。
解析:重心 = 删去后最大连通块最小的点—— 子树大小与 取 max 比较。✅ 正确
排除法:无(判断题)。混淆点:L3 实测 1-2-3/4/5 树重心为 2。
关联 · L3 代码:重心实测。
判断题:树上最大独立集——(不选 u)取儿子选不选的 max 之和,(选 u)取儿子不选之和。
考点:最大独立集(E4)。
解析:(不选 u)取儿子选不选的 max 之和;(选 u)取儿子不选之和。✅ 正确
排除法:无(判断题)。混淆点:L2 实测 6 点树独立集 4。
关联 · L2 代码:独立集实测。
判断题:树上背包——在 DFS 序/子树合并中做容量维 DP, 或 ,是分组背包的树上版。
考点:树上背包(E5)。
解析:在子树合并中做容量维 DP, 或 ——分组背包的树上版。✅ 正确
排除法:无(判断题)。混淆点:L4 依赖背包是其特例。
关联 · C5 依赖背包:父子依赖 = 树。
判断题:换根 DP——先以 1 为根算一遍,再沿边"把根换过去", 求所有点为根的答案。
考点:换根思想(E6)。
解析:先以 1 为根算一遍,再沿边"把根换过去", 求所有点为根的答案。✅ 正确
排除法:无(判断题)。混淆点:L6 链 1-2-3 距离和 {3,2,3}。
关联 · L6 代码:换根实测。
状压 DP 的状态定义是?
考点:状态定义(F1)。
解析:二进制数表示集合——第 位 = 元素 是否在集合中, 为该局面最优值。✅ 正确
排除法:B/C/D 不是状压。
关联 · F2 位运算:状态的读写全靠位运算。
状压常用位运算是?
考点:位运算(F2)。
解析:1<<i 造位、mask|(1<<i) 加元素、mask&(1<<i) 判存在、mask^(1<<i) 删元素。✅ 正确
排除法:B/C/D 无关。
关联 · M 组代码:M1/M4 全用位运算。
判断题:枚举 mask 的所有子集可用 for (sub = mask; sub; sub = (sub-1) & mask)——总复杂度 。
考点:子集枚举(F3)。
解析:for (sub = mask; sub; sub = (sub-1) & mask) 枚举全部子集,总复杂度 。✅ 正确
排除法:无(判断题)。混淆点:M1 实测 mask=5 → 5 4 1 0。
关联 · M1 代码:子集枚举实例。
判断题:旅行商问题(TSP)状压 DP—— 表示走过集合 mask、当前在点 i 的最小代价,逐点扩展; 量级可用。
考点:旅行商思想(F4)。
解析: = 走过集合 mask、当前在 i 的最小代价—— 量级可用( 状态)。✅ 正确
排除法:无(判断题)。混淆点:M2 实测 4 城回路 9。
关联 · M2 代码:TSP 实测。
判断题:轮廓线 DP(插头 DP 雏形)——逐格处理棋盘类问题,状态只记录"当前轮廓线"上的信息。
考点:轮廓线思想(F5)。
解析:逐格处理棋盘,状态只记录"当前轮廓线"上的信息——插头 DP 的雏形。✅ 正确
排除法:无(判断题)。混淆点:S 组了解思想即可。
关联 · F6 适用判断:棋盘 + 逐格 = 轮廓线。
判断题:适用判断——元素个数 左右、状态天然是"选/不选"集合时,考虑状压 DP。
考点:适用判断(F6)。
解析: 左右、状态天然是"选/不选"集合时考虑状压 DP。✅ 正确
排除法:无(判断题)。混淆点: 时 约 ,通常超时超内存。
关联 · G6 优化选择:按规模选工具。
判断题:滚动数组——转移只依赖上一行/上一阶段时,用 i&1(或交换指针)交替使用两行,空间降一维。
考点:滚动数组(G1)。
解析:转移只依赖上一阶段时用 i&1 交替两行——空间降一维。✅ 正确
排除法:无(判断题)。混淆点:O7 填空 i & 1。
关联 · O7 代码:滚动数组填空。
判断题:记忆化搜索 = 递归 + 查表——把"算过的状态"存下来,状态图是无环图(或按拓扑序)时等价于 DP。
考点:记忆化搜索(G2)。
解析:递归 + 查表——算过的状态存下来;状态图无环(或按拓扑序)时等价于 DP。✅ 正确
排除法:无(判断题)。混淆点:有环递归会死循环/漏算。
关联 · A3 无后效性:记忆化也要求状态无环依赖。
判断题:单调队列优化——形如 的滑动窗口最值转移,用单调队列 取窗口最值。
考点:单调队列优化(G3)。
解析: 类滑动窗口最值转移——单调队列 取窗口最值。✅ 正确
排除法:无(判断题)。混淆点:衔接第 30 章单调队列。
关联 · 第 30 章单调队列:数据结构为 DP 服务。
判断题:斜率优化是 的通用 DP 优化,任何递推都能套用。
考点:斜率优化思想(G4)。
解析:斜率优化不是 通用优化——只适用于转移可写成 凸包形式的特定 DP(如玩具装箱类)。✅ 答案 B(错误)
排除法:无(判断题)。混淆点:S 组了解"用单调队列维护凸包"思想即可。
关联 · G3 单调队列优化:凸包用单调队列维护。
判断题:状态压缩——把"是否选/访问过"等布尔信息压进一个整数的二进制位,从而把状态变成下标。
考点:状态压缩(G5)。
解析:把"是否选/访问过"等布尔信息压进整数二进制位——状态变下标。✅ 正确
排除法:无(判断题)。混淆点:状压 DP 的命名来源。
关联 · F1 状态定义:同一件事。
优化选择流程是?
考点:优化选择(G6)。
解析:按转移结构选——只依赖上一阶段→滚动;窗口最值→单调队列;布尔集合→状压;递归易写→记忆化。✅ 正确
排除法:B/C/D 一刀切。
关联 · 本章各优化:选择矩阵。
判断题:初值设置——求 min 的 DP 初始化 INF、求 max 初始化 -INF/0,起点状态单独赋值;初值错全盘错。
考点:初值设置(H1)。
解析:求 min 初始化 INF、求 max 初始化 -INF/0,起点状态单独赋值——初值错全盘错。✅ 正确
排除法:无(判断题)。混淆点:区间 DP 的 dp[i][i]=0、背包 f[0]=0。
关联 · K 组代码:dp 初值 INF。
判断题:循环顺序——01 背包逆序、完全背包正序、区间 DP 按长度、树形 DP 后序;顺序错结果错。
考点:循环顺序(H2)。
解析:01 逆序、完全正序、区间按长度、树形后序——顺序错结果错。✅ 正确
排除法:无(判断题)。混淆点:P1/P2/P3 三种顺序错都有实证。
关联 · P 组易错:顺序错实证。
判断题:空间溢出—— 的 int 数组约 100MB(5001²×4B),接近常见内存上限,注意用滚动数组或小类型。
考点:空间溢出(H3)。
解析: 的 int 数组约 100MB(B),接近内存上限——用滚动数组或小类型。✅ 正确
排除法:无(判断题)。混淆点:验算 5001²×4 = 100,040,004 ≈ 95.4 MB。
关联 · G1 滚动数组:压空间的动机。
判断题:环形处理——环形序列问题复制一倍断环成链,注意答案取"所有长度为 n 的窗口"而非固定一段。
考点:环形处理(H4)。
解析:环形序列复制一倍断环成链,答案取"所有长度为 n 的窗口"而非固定一段。✅ 正确
排除法:无(判断题)。混淆点:K3 环形石子取 3 个窗口的最小值 19。
关联 · D3 断环成链:同一手法。
判断题:以下结论全部正确——"LIS 二分优化 ;01 逆序、完全正序;区间 DP 按长度枚举;树形 DP 后序合并;状压只适合 n 很小;滚动数组只留必要维度"。
考点:综合判断(H5)。
解析:六结论全对——LIS 二分 ;01 逆序、完全正序;区间按长度;树形后序;状压只适合 n 小;滚动数组只留必要维度。✅ 正确
排除法:无(判断题)。混淆点:本章核心结论自检清单。
关联 · 本章全部核心结论:收官判断题。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 8; 05 int a[9] = {0, 3, 1, 4, 1, 5, 9, 2, 6}; // 下标 1 起 06 int dp[9]; 07 for (int i = 1; i <= n; i++) { 08 dp[i] = 1; 09 for (int j = 1; j < i; j++) 10 if (a[j] < a[i]) dp[i] = max(dp[i], dp[j] + 1); 11 } 12 int ans = 0; 13 for (int i = 1; i <= n; i++) ans = max(ans, dp[i]); 14 cout << ans; 15 return 0; 16}
单选题:程序输出是?(LIS 长度)
考点:LIS 长度(I1)。
解析:数组 {3,1,4,1,5,9,2,6}:最长上升子序列 1,4,5,9(或 1,4,5,6 等),长度 4。✅ 答案 A
排除法:B 3 漏了 9;C 5 不存在;D 2 只数了一半。
关联 · B2 LIS 转移:dp[j]+1 逐点接龙。
01// 代码与 I1 完全相同,最后输出 dp 数组: 02for (int i = 1; i <= n; i++) cout << dp[i] << " ";
单选题:程序输出是?(以 i 结尾的 LIS 长度)
考点:以 i 结尾的 LIS(I2)。
解析:dp[7](a=2)只能接在 1 后面 = 2,不是 3;dp[8](a=6)接 5 得 4。数组 1 1 2 1 3 4 2 4。✅ 答案 D
排除法:A/B/C 在 dp[7] 或 dp[8] 算错。
关联 · B2 转移:逐位手算。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 8; 05 int a[9] = {0, 3, 1, 4, 1, 5, 9, 2, 6}; 06 vector<int> tail; // 最小结尾数组 07 for (int i = 1; i <= n; i++) { 08 auto it = lower_bound(tail.begin(), tail.end(), a[i]); 09 if (it == tail.end()) tail.push_back(a[i]); 10 else *it = a[i]; 11 } 12 cout << tail.size(); 13 return 0; 14}
单选题:程序输出是?
考点:tail 长度(I3)。
解析:tail 依次为 [3]→[1]→[1,4]→[1,4]→[1,4,5]→[1,4,5,9]→[1,2,5,9]→[1,2,5,6],长度 4。✅ 答案 B
排除法:A/C/D 长度错。
关联 · B4 二分优化:lower_bound 替换。
01// 代码与 I3 完全相同,最后输出 tail 数组(注意:tail 不是真正的 LIS): 02for (int x : tail) cout << x << " ";
单选题:程序输出是?
考点:tail 内容(I4)。
解析:tail 最终 = 1 2 5 6——注意它不是真实 LIS(真实 LIS 是 1,4,5,9 等)。✅ 答案 C
排除法:A/B 保留 9;D 开头 3 早被替换。
关联 · B4:tail ≠ LIS,只借长度。
01for (int i = 1; i <= n; i++) { 02 dp[i] = 1; 03 for (int j = 1; j < i; j++) 04 if (a[j] < a[i]) dp[i] = max(dp[i], ______); // 接在 j 后面 05}
单选题:横线处应填入?
考点:接龙转移(I5)。
解析:接在 j 后面 = dp[j] + 1。✅ 答案 A
排除法:B 漏 +1;C 自接;D 减 1 无意义。
关联 · B2 转移:填空即转移式。
// 数组换成 {0, 5, 1, 6, 2, 7, 3}(n = 6,下标 1 起),O(n²) 求 LIS
单选题:程序输出是?
考点:另一数组(I6)。
解析:{5,1,6,2,7,3}:LIS 为 1,2,3(或 5,6,7),长度 3。✅ 答案 C
排除法:A 2 只数到 6 前的;B/D 无依据。
关联 · I1:同法不同数据。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int W = 7; 05 int w[4] = {0, 2, 3, 4}; // 3 件物品的重量 06 int v[4] = {0, 3, 4, 5}; // 价值 07 int f[8] = {0}; 08 for (int i = 1; i <= 3; i++) 09 for (int j = W; j >= w[i]; j--) 10 f[j] = max(f[j], f[j - w[i]] + v[i]); 11 cout << f[W]; 12 return 0; 13}
单选题:程序输出是?(最大价值)
考点:01 背包最大值(J1)。
解析:选物品 2+3(重 3+4=7,价值 4+5=9)最优。f[7]=9。✅ 答案 D
排除法:A 7 是 2+3 物品;B 8 是 2+4 物品;C 10 无依据。
关联 · C1 01 背包:逆序容量。
01// 代码与 J1 完全相同,最后输出 f[0..7]: 02for (int j = 0; j <= W; j++) cout << f[j] << " ";
单选题:程序输出是?
考点:f[0..7] 全过程(J2)。
解析:逐物品:f = 0 0 3 4 5 7 8 9(f[7]=9、f[6]=8、f[5]=7)。✅ 答案 A
排除法:B/C/D 在 f[5]/f[6] 细节错。
关联 · C1:一维数组全貌。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int W = 7; 05 int w[3] = {0, 2, 3}; 06 int v[3] = {0, 3, 4}; 07 int f[8] = {0}; 08 for (int i = 1; i <= 2; i++) 09 for (int j = w[i]; j <= W; j++) // 正序 10 f[j] = max(f[j], f[j - w[i]] + v[i]); 11 cout << f[W]; 12 return 0; 13}
单选题:程序输出是?
考点:完全背包(J3)。
解析:物品无限:2×2+3=7 → 3+3+4=10(2 件重 2 + 1 件重 3)。f[7]=10。✅ 答案 C
排除法:A 7 少算;B 9 只取 3 件重 2;D 6 无依据。
关联 · C2 完全背包:正序容量。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w = 2, v = 3, c = 4; // 重量 2、价值 3、共 4 件 05 vector<pair<int,int>> items; 06 for (int k = 1; c > 0; k *= 2) { 07 int t = min(k, c); 08 items.push_back({w * t, v * t}); // 打包 t 件 09 c -= t; 10 } 11 cout << items.size() << " "; 12 for (auto [ww, vv] : items) cout << ww << " " << vv << " "; 13 return 0; 14}
单选题:程序输出是?(拆成的包数与每包的重量价值)
考点:二进制拆包(J4)。
解析:c=4 → 1 件包 (2,3)、2 件包 (4,6)、1 件包 (2,3),共 3 包。✅ 答案 B
排除法:A 顺序错;C 拆成 4 个 1 件包(非二进制);D 一包全打包(不能表示任意件数)。
关联 · C3 多重拆分:1,2,1 组合出 0..4 任意件。
01for (int i = 1; i <= n; i++) 02 for (int j = W; ______; j--) // 01 背包容量逆序 03 f[j] = max(f[j], f[j - w[i]] + v[i]);
单选题:横线处应填入?
考点:容量边界(J5)。
解析:逆序到 j >= w[i] 为止(装得下才转移)。✅ 答案 A
排除法:B j >= 0 会访问 f[负数];C/D 方向错。
关联 · C1:循环三要素(起点/终点/方向)。
// 一件 01 物品(重量 2 价值 3)+ 一件完全物品(重量 3 价值 4),容量 6 // 先处理 01(逆序),再处理完全(正序),输出 f[6]
单选题:程序输出是?
考点:01 + 完全混合(J6)。
解析:01(2,3) 后 f[2]=3;完全(3,4) 后 f[6]=f[3]+4=8(3+4 的完全用两次)。✅ 答案 A
排除法:B 7 漏一次完全;C/D 无依据。
关联 · C6 混合背包:两段处理。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 3; 05 int a[4] = {0, 4, 5, 3}; 06 int s[4] = {0}; 07 for (int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i]; 08 int dp[4][4]; 09 memset(dp, 0x3f, sizeof dp); 10 for (int i = 1; i <= n; i++) dp[i][i] = 0; 11 for (int len = 2; len <= n; len++) 12 for (int i = 1; i + len - 1 <= n; i++) { 13 int j = i + len - 1; 14 for (int k = i; k < j; k++) 15 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + s[j] - s[i - 1]); 16 } 17 cout << dp[1][n]; 18 return 0; 19}
单选题:程序输出是?(合并最小代价)
考点:合并最小代价(K1)。
解析:{4,5,3}:先 (5+3)=8 再 (4+8)=12,总 20。✅ 答案 B
排除法:A 21 是先 (4+5) 的顺序;C/D 无依据。
关联 · D2 石子合并:枚举 k 取 min。
// 图与 K1 完全相同,最后输出: cout << dp[1][2] << " " << dp[2][3];
单选题:程序输出是?(相邻两堆的合并代价)
考点:相邻两堆代价(K2)。
解析:dp[1][2]=4+5=9、dp[2][3]=5+3=8。✅ 答案 C
排除法:A/B/D 数值对调或错。
关联 · K1:长度为 2 的基准值。
// 环形石子:{4,5,3} 首尾相接。断环成链:复制一倍 {4,5,3,4,5,3}
// 对每个长度为 3 的窗口 [i, i+2] 跑石子合并,取最小值
// 窗口 [3,5] = {3,4,5}:(3+4)=7,(7+5)=12,总代价 19
单选题:程序输出是?(环形合并最小代价)
考点:断环成链(K3)。
解析:三个窗口:{4,5,3}=20、{5,3,4}=20、{3,4,5}=19,取 19。✅ 答案 A
排除法:B 20 漏了 {3,4,5} 窗口;C/D 无依据。
关联 · D3 断环成链:窗口全枚举。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 5; 05 int a[6] = {0, 1, 2, 2, 1, 3}; 06 int dp[6][6] = {0}; 07 for (int i = 1; i <= n; i++) dp[i][i] = 1; 08 for (int len = 2; len <= n; len++) 09 for (int i = 1; i + len - 1 <= n; i++) { 10 int j = i + len - 1; 11 if (a[i] == a[j]) dp[i][j] = dp[i + 1][j - 1] + 2; 12 else dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); 13 } 14 cout << dp[1][n]; 15 return 0; 16}
单选题:程序输出是?(最长回文子序列长度)
考点:LPS(K4)。
解析:{1,2,2,1,3}:1,2,2,1 是长度 4 的回文子序列。✅ 答案 D
排除法:A 2 只取 2,2;B 5 需要整个序列回文(不是);C 3 漏了。
关联 · D6 回文:首尾相等 +2。
01for (int k = i; k < j; k++) 02 dp[i][j] = min(dp[i][j], dp[i][k] + ______ + s[j] - s[i - 1]);
单选题:横线处应填入?
考点:分割点右半(K5)。
解析:左半 [i,k] 加右半 [k+1,j]:dp[k + 1][j]。✅ 答案 A
排除法:B 左半自身;C/D 下标错。
关联 · D2 转移:k 分割两半。
01for (int len = 2; len <= n; len++) { 02 cout << len << " "; 03 for (int i = 1; i + len - 1 <= n; i++) { 04 int j = i + len - 1; 05 for (int k = i; k < j; k++) 06 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + s[j] - s[i - 1]); 07 } 08} 09// n = 3 时,外层循环输出:
单选题:程序输出是?(len 的取值序列)
考点:len 序列(K6)。
解析:len 从 2 到 n=3,输出 2 3。✅ 答案 B
排除法:A 含 1(len=1 是初值不用算);C/D 顺序错。
关联 · D4 长度枚举:外层 len。
// 石子 {1,3,5,2}(n = 4),标准石子合并,输出 dp[1][4]
单选题:程序输出是?
考点:四堆合并(K7)。
解析:{1,3,5,2}:最优合并代价 22。✅ 答案 C
排除法:A 20 是 {4,5,3} 的答案;B/D 无依据。
关联 · D2:n=4 全流程。
01#include <bits/stdc++.h> 02using namespace std; 03vector<int> g[7]; 04int ans = 0; 05int dfs(int u, int fa) { 06 int d1 = 0, d2 = 0; // 子树中最长链与次长链(不同子树) 07 for (int v : g[u]) { 08 if (v == fa) continue; 09 int d = dfs(v, u) + 1; 10 if (d > d1) { d2 = d1; d1 = d; } 11 else if (d > d2) d2 = d; 12 } 13 ans = max(ans, d1 + d2); 14 return d1; 15} 16int main() { 17 int e[5][2] = {{1,2}, {1,3}, {2,4}, {2,5}, {3,6}}; // 6 个点 5 条边 18 for (auto [u, v] : e) { g[u].push_back(v); g[v].push_back(u); } 19 dfs(1, 0); 20 cout << ans; 21 return 0; 22}
单选题:程序输出是?(树的直径)
考点:树直径(L1)。
解析:6 点树最长链 4-2-1-3-6(或 5-2-1-3-6),长 4;根 1 处 d1=d2=2,ans=4。✅ 答案 A
排除法:B 3 漏一端;C/D 无依据。
关联 · E2 直径:d1+d2 拼接。
// 树同 L1(6 个点)。树上最大独立集: // dp[u][0] = 不选 u:儿子选不选取 max 之和 // dp[u][1] = 选 u:儿子都不选之和
单选题:程序输出是?(最大独立集大小)
考点:树上独立集(L2)。
解析:选 {1,4,5,6}(或 {2,3} 只有 2),最大 4。✅ 答案 C
排除法:A 3 漏一个叶子;B 2 是 {2,3};D 5 不可能(6 点树独立集 ≤ 4)。
关联 · E4 独立集:选/不选两状态。
// 树:1-2、2-3、2-4、2-5(5 个点) // sz[u] = 子树大小;删掉点 u 后最大连通块 = max(各儿子 sz, n - sz[u]) // 重心 = 最大连通块最小的点
单选题:程序输出是?(重心编号与最大连通块大小)
考点:重心与最大块(L3)。
解析:删 2 后剩 {1},{3},{4},{5} 各 1 个点,最大块 1——重心为 2。✅ 答案 B
排除法:A/D 最大块算错;C 重心对但块大小错。
关联 · E3 重心:max(儿子 sz, n-sz)。
// 依赖背包:树为链 1-2-3,选节点必须已选父节点;价值 v = {1, 2, 3}
// 最多选 m = 2 个节点,求最大价值
// 合法选法:{} = 0、{1} = 1、{1,2} = 3({2}、{3}、{2,3} 不合法)
单选题:程序输出是?
考点:依赖背包(L4)。
解析:选节点须选父节点:{1,2}=3 最优({1,2,3} 超 2 个)。✅ 答案 A
排除法:B 5 是 {2,3}(不合法);C 6 全选(超数);D 2 只选 2(不合法)。
关联 · E5 树上背包:父子依赖。
01int dfs(int u, int fa) { 02 int d1 = 0, d2 = 0; 03 for (int v : g[u]) { 04 if (v == fa) continue; 05 int d = dfs(v, u) + 1; 06 if (d > d1) { d2 = d1; d1 = d; } 07 else if (d > d2) d2 = d; 08 } 09 ans = max(ans, ______); // 两条链穿过 u 拼接 10 return d1; 11}
单选题:横线处应填入?
考点:直径拼接(L5)。
解析:穿过 u 的最长链 = d1 + d2。✅ 答案 B
排除法:A 只一条链(漏拼接);C/D 无意义。
关联 · L1:填空即核心行。
// 树为链 1-2-3。换根 DP 求每个点到其他所有点的距离和: // 以 1 为根:dist[1] = 0+1+2 = 3 // 换根到 2:dist[2] = 1+0+1 = 2 // 换根到 3:dist[3] = 2+1+0 = 3
单选题:程序输出是?
考点:距离和换根(L6)。
解析:链 1-2-3:以 1 为根 {0,1,2} 和 3;换到 2 得 {1,0,1} 和 2;换到 3 得 3。输出 3 2 3。✅ 答案 D
排除法:A 是距离数组;B/C 数值错。
关联 · E6 换根:沿边换根。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int mask = 5; // 101 = {1, 3} 05 for (int sub = mask; ; sub = (sub - 1) & mask) { 06 cout << sub << " "; 07 if (sub == 0) break; 08 } 09 return 0; 10}
单选题:程序输出是?(mask = 5 的全部子集)
考点:子集枚举顺序(M1)。
解析:mask=5(101) 的子集:5→4→1→0((sub-1)&mask 递减序)。✅ 答案 A
排除法:B 1 与 4 顺序反;C 是升序;D 无依据。
关联 · F3 子集枚举:递减枚举式。
// 4 个城市,完全图距离:d12=2, d13=5, d14=4, d23=1, d24=6, d34=2 // 状压 DP:dp[mask][i] = 走过集合 mask、当前在 i 的最小代价,从城市 1 出发 // dp[1<<0][0] = 0;最后答案 = min(dp[(1<<4)-1][i] + d[i][0])
单选题:程序输出是?(绕一圈回到 1 的最短回路)
考点:TSP 最短回路(M2)。
解析:1-2-3-4-1 = 2+1+2+4 = 9(或 1-4-3-2-1 同值),最优 9。✅ 答案 C
排除法:A/B 是 1-3-2-4-1 等劣环;D 无依据。
关联 · F4 TSP:状压 + 环闭合。
// 3 个点的链 1-2-3,点权 {1, 2, 3},求最大权独立集(不相邻)
// 枚举 0..(1<<3)-1 中合法子集(无相邻位 1):{}、{1}、{2}、{3}、{1,3}
// 权值和分别为 0、1、2、3、4,最大 4
单选题:程序输出是?
考点:状压枚举合法集(M3)。
解析:3 点链无相邻位集合:{}、{1}、{2}、{3}、{1,3},权最大 1+3=4。✅ 答案 B
排除法:A 3 漏 {1,3};C/D 含相邻非法集。
关联 · F1 状态定义:位 = 选/不选。
01for (int j = 0; j < n; j++) { 02 if (______) continue; // j 已在集合中 03 int nmask = mask | (1 << j); 04 dp[nmask][j] = min(dp[nmask][j], dp[mask][i] + d[i][j]); 05}
单选题:横线处应填入?
考点:判元素在集合中(M4)。
解析:mask & (1 << j) 非 0 表示 j 已在集合中。✅ 答案 A
排除法:B 是加元素;C 是删除;D 无意义。
关联 · F2 位运算:判存在。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int x = 13; // 1101 05 int cnt = 0; 06 while (x) { cnt += x & 1; x >>= 1; } 07 cout << cnt; 08 return 0; 09}
单选题:程序输出是?(13 的二进制中 1 的个数)
考点:popcount(M5)。
解析:13 = 1101,含 3 个 1。✅ 答案 C
排除法:A/B/D 数错。
关联 · F2 位运算:x&1 取最低位。
// n = 4 个元素,枚举 0 .. (1<<4)-1 共 16 个集合,统计元素个数 >= 2 的集合数 // 总数 16,空集 1 个、单元素 4 个 → 16 - 1 - 4 = 11
单选题:程序输出是?
考点:集合计数(M6)。
解析:4 元素共 16 个子集,≥2 元素的 = 16-1-4 = 11。✅ 答案 D
排除法:A 16 含空集单元素;B/C 数错。
关联 · F3 子集枚举:全集规模 2^n。
// 数组 {3,1,4,1,5,9,2,6},用 lower_bound 二分求 LIS 长度
单选题:程序输出是?
考点:二分求 LIS(N1)。
解析:{3,1,4,1,5,9,2,6} 的 LIS 长度 4。✅ 答案 B
排除法:A/C/D 长度错。
关联 · I3:同题回顾。
// 4 件物品:w = {2,3,4,5}, v = {3,4,5,6},容量 10,标准 01 背包
// f[10] = max(3+4+5 需 2+3+4=9 价值 12, 4+5+6 需 3+4+5=12 超, 3+4+6 需 10 价值 13)
单选题:程序输出是?(最大价值)
考点:四物品背包(N2)。
解析:w={2,3,4,5}, v={3,4,5,6}, W=10:2+3+5 重 10 价值 3+4+6=13 最优。✅ 答案 D
排除法:A 12 是 2+3+4 三件;B/C 无依据。
关联 · J1:n=4 扩展。
// 环形石子 {4,5,3},断环成链后枚举所有长度为 3 的窗口取最小合并代价
单选题:程序输出是?
考点:环形合并(N3)。
解析:{4,5,3} 环形最优窗口 {3,4,5} → 19。✅ 答案 A
排除法:B 20 是直链;C/D 无依据。
关联 · K3:同题回顾。
// 树同 L1,两次 DFS 求直径:从 1 出发最远点为 4(距离 2),从 4 出发最远点为 6(距离 4)
单选题:程序输出是?
考点:两次 DFS 直径(N4)。
解析:从 1 最远 4(距离 2),从 4 最远 6(距离 4)——直径 4。✅ 答案 C
排除法:A 2 只是第一段;B/D 无依据。
关联 · E2/L1:两次 DFS 与 DP 殊途同归。
01int full = ______; // n 个元素全选的全集掩码
单选题:横线处应填入?
考点:全集掩码(N5)。
解析:n 位全 1 = (1 << n) - 1。✅ 答案 A
排除法:B 是第 n+1 位;C 多 1;D 是 n×2。
关联 · F1 状态定义:全集下标。
// 混合背包:01 物品(2,3)+ 完全物品(3,4),容量 6 // 先 01 逆序再完全正序,输出 f[6]
单选题:程序输出是?
考点:混合背包(N6)。
解析:01(2,3)+完全(3,4) W=6 → 8(完全用两次 3+4+...)。✅ 答案 B
排除法:A 7 漏一次完全;C/D 无依据。
关联 · J6:同题回顾。
01for (int i = 1; i <= n; i++) { 02 auto it = ①; // 第一个 >= a[i] 的位置 03 if (it == tail.end()) tail.push_back(a[i]); 04 else *it = a[i]; 05}
单选题:①处应填?
考点:lower_bound(O1)。
解析:严格上升用 lower_bound(第一个 ≥)。✅ 答案 A
排除法:B upper_bound 用于不下降;C find 只找相等;D 取首迭代器错。
关联 · B4 二分优化:lower/upper 之别。
01for (int i = 1; i <= n; i++) 02 for (int j = W; j >= w[i]; j--) 03 f[j] = max(f[j], ①);
单选题:①处应填?
考点:01 转移式(O2)。
解析:f[j - w[i]] + v[i]。✅ 答案 B
排除法:A 不是转移式;C 漏价值;D 下标错。
关联 · C1:填空即转移。
01for (int i = 1; i <= n; i++) 02 for (int j = ①; j <= W; j++) // 完全背包:正序 03 f[j] = max(f[j], f[j - w[i]] + v[i]);
单选题:①处应填?
考点:正序起点(O3)。
解析:从 w[i] 起正序到 W。✅ 答案 C
排除法:A 0 会访问负下标;B 1 漏 0~w-1 容量;D 终点错。
关联 · C2 完全背包:起点 = 装得下。
01for (int len = 2; len <= n; len++) 02 for (int i = 1; i + len - 1 <= n; i++) { 03 int j = i + len - 1; 04 for (int k = i; k < j; k++) 05 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + ①); 06 }
单选题:①处应填?(合并两堆的代价)
考点:合并代价(O4)。
解析:两堆合并代价 = 区间和 s[j] - s[i-1]。✅ 答案 A
排除法:B 只取前缀;C 只两端点;D 无意义。
关联 · D2 石子合并:前缀和优化。
01// 树上最大独立集 02dp[u][1] = 1; 03for (int v : g[u]) { 04 if (v == fa) continue; 05 dfs(v, u); 06 dp[u][0] += max(dp[v][0], dp[v][1]); 07 dp[u][1] += ①; // 选了 u,儿子都不能选 08}
单选题:①处应填?
考点:独立集选点分支(O5)。
解析:选了 u 则儿子都不能选:加 dp[v][0]。✅ 答案 D
排除法:A 是不选分支的;B/C 允许儿子被选(相邻冲突)。
关联 · E4 独立集:两分支别混。
01for (int mask = 0; mask < (1 << n); mask++) 02 for (int i = 0; i < n; i++) 03 if (dp[mask][i] == INF) continue; 04 else { 05 for (int j = 0; j < n; j++) { 06 if (①) continue; // j 已访问过 07 int nmask = mask | (1 << j); 08 dp[nmask][j] = min(dp[nmask][j], dp[mask][i] + d[i][j]); 09 } 10 }
单选题:①处应填?
考点:判已访问(O6)。
解析:mask & (1 << j) 非 0 → j 已访问,跳过。✅ 答案 B
排除法:A/C/D 语义错。
关联 · M4:同填空再考。
01for (int i = 1; i <= n; i++) { 02 int cur = ①, pre = cur ^ 1; // 交替两行 03 for (int j = 1; j <= m; j++) 04 dp[cur][j] = max(dp[pre][j], dp[pre][j - w[i]] + v[i]); 05}
单选题:①处应填?
考点:交替行(O7)。
解析:cur = i & 1、pre = cur ^ 1 交替两行。✅ 答案 C
排除法:A/B 会越界;D 语法错。
关联 · G1 滚动数组:i&1 通用写法。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int W = 4; 05 int w[2] = {0, 2}, v[2] = {0, 3}; // 只有一件物品 06 int f[5] = {0}; 07 for (int i = 1; i <= 1; i++) 08 for (int j = w[i]; j <= W; j++) // 注意:写成了正序 09 f[j] = max(f[j], f[j - w[i]] + v[i]); 10 cout << f[W]; 11 return 0; 12}
单选题:程序输出是?(01 背包正确结果应为 3)
考点:正序导致重复使用(P1)。
解析:正序时 f[4] = f[2]+3,而 f[2] 已含该物品 → 6(用了两次)。✅ 答案 C
排除法:A 3 是正确结果;B/D 无依据。
关联 · C1/C2:正逆序是 01/完全的分水岭。
01// 石子 {4,5,3},但循环写成了 i 在外层、j 在内层(未按长度枚举): 02for (int i = 1; i <= n; i++) 03 for (int j = i + 1; j <= n; j++) 04 for (int k = i; k < j; k++) 05 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + s[j] - s[i - 1]); 06// 求 dp[1][3] 时 dp[2][3] 还没算(仍为 INF),只有 k=2 的分支有效:9 + 0 + 12 = 21
单选题:程序输出是?(正确结果应为 20)
考点:未按长度枚举(P2)。
解析:求 dp[1][3] 时 dp[2][3] 还是 INF,只有 k=2 分支有效:9+0+12=21。✅ 答案 C
排除法:A/B/D 无依据(正确结果 20)。
关联 · D4 长度枚举:顺序错 = 用未算状态。
01// 完全背包(物品无限),但写成了逆序: 02int W = 4; 03int w[2] = {0, 2}, v[2] = {0, 3}; 04int f[5] = {0}; 05for (int i = 1; i <= 1; i++) 06 for (int j = W; j >= w[i]; j--) // 注意:写成了逆序 07 f[j] = max(f[j], f[j - w[i]] + v[i]); 08cout << f[W];
单选题:程序输出是?(完全背包正确结果应为 6——用两次)
考点:逆序导致只用一次(P3)。
解析:逆序时 f[4] = f[2]+3,f[2] 还没更新 → 3(正确 6)。✅ 答案 B
排除法:A 6 是正确结果;C/D 无依据。
关联 · C2/P1:与 P1 镜像。
01// 石子 {4,5,3},转移漏掉了 + s[j] - s[i-1]: 02for (int k = i; k < j; k++) 03 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]); // 注意:忘加两堆和
单选题:程序输出是?(正确结果应为 20)
考点:漏合并代价(P4)。
解析:不加 sum 项,所有 dp 恒为 0(dp[i][i]=0 传递)→ 输出 0。✅ 答案 D
排除法:A 20 是正确结果;B/C 无依据。
关联 · D2 转移:+sum 是代价核心。
01// 树同 L1,DFS 只返回最长链 d1,但漏掉了 ans = max(ans, d1 + d2); 02int dfs(int u, int fa) { 03 int d1 = 0, d2 = 0; 04 for (int v : g[u]) { 05 if (v == fa) continue; 06 int d = dfs(v, u) + 1; 07 if (d > d1) { d2 = d1; d1 = d; } 08 else if (d > d2) d2 = d; 09 } 10 // 注意:漏掉了 ans 的更新 11 return d1; 12} 13// 最后输出 ans(因漏更新始终为 0)
单选题:程序输出是?(正确直径应为 4)
考点:漏 ans 更新(P5)。
解析:只返回 d1 不更新 ans——ans 恒 0,直径 4 永远得不到。✅ 答案 B
排除法:A 4 是正确结果;C/D 无依据。
关联 · L5 填空:d1+d2 那行不能丢。
判断题:以下五种易错写法都会导致程序出错——①01 背包写成正序(物品被重复使用)②区间 DP 不按长度枚举(用到的子区间还没算)③完全背包写成逆序(物品只能用一次)④石子合并忘加两堆和(代价少算)⑤树形 DP 直径忘更新 ans(答案始终为 0)。
考点:五种易错综合判断(P6)。
解析:五条全对——01 正序重复用、区间不按长度用未算状态、完全逆序只用一次、石子忘加和全 0、直径忘更新恒 0。✅ 正确
排除法:无(判断题)。混淆点:每条对应 P1~P5 一道实证题。
关联 · P1~P5:易错清单自查。