判断题:贪心 = 每一步都做"当前看起来最好"的选择(局部最优),希望由此得到全局最优解。
考点:贪心的定义(A1)。
解析:贪心 = 每一步做当前最优选择(局部最优),希望积累出全局最优。✅ 正确
排除法:无(判断题)。混淆点:贪心是"一条路走到底",不做回溯、不比较多种方案。
关联 · 贪心不是万能的(A2):局部最优不一定全局最优。
判断题:局部最优不一定是全局最优——贪心对有些问题给正确答案,对另一些问题给错误答案,必须具体问题具体分析。
考点:贪心不是万能的(A2)。
解析:贪心对有的问题给最优解(活动安排)、有的给次优解(0/1 背包)——必须具体分析。✅ 正确
排除法:无(判断题)。混淆点:判断贪心是否成立靠"贪心选择性质 + 最优子结构"(A3/A4)。
关联 · 贪心选择性质(A3):成立与否决定贪心对错。
判断题:若一个问题具有贪心选择性质,则每一步的贪心选择都能通向全局最优解。
考点:贪心选择性质(A3)。
解析:具有贪心选择性质的问题,第一步贪心选择必属于某个最优解,逐步贪心可到全局最优。✅ 正确
排除法:无(判断题)。混淆点:这是贪心正确性的"入场券"——没有它就不能贪。
关联 · 贪心证明的结构(F1):贪心选择性质是证明的一半。
判断题:最优子结构 = 问题的最优解包含其子问题的最优解——贪心与动态规划都需要这个性质。
考点:最优子结构(A4)。
解析:问题最优解包含子问题最优解——贪心与 DP 都依赖这个性质。✅ 正确
排除法:无(判断题)。混淆点:只有最优子结构还不够,贪心还需要"当前选择不会破坏后续最优"。
关联 · 贪心与动态规划(E1):两算法共享该前提。
单选题:与枚举、动态规划相比,贪心的典型特征是?
考点:贪心与枚举动态规划(A5)。
解析:贪心每步锁定一个选择、复杂度低(常 ),代价是不保证全局最优。正确答案 A。
排除法:B 是"保证正确"的算法特征;C 说反;D 是回溯。
关联 · 贪心的复杂度(D6): 的来源。
判断题:验证贪心是否成立的最快方法是构造反例;找不到反例不等于证明正确,但竞赛中常用"小数据对拍 + 找反例"来检验。
考点:用反例验证贪心(A6)。
解析:构造反例是最快的检验手段;竞赛中常用"小数据对拍 + 找反例"验证贪心。✅ 正确
排除法:无(判断题)。混淆点:找不到反例 ≠ 证明正确,但实战中足够。
关联 · 反例否定贪心(F5):一个反例即否定。
判断题:人民币硬币面额(1、5、10、20、50、100 元)下,"每次取不超过剩余金额的最大面额"的找零贪心能得到最少张数——因为大面额都是小面额的倍数。
考点:找零钱的贪心(B1)。
解析:人民币面额大面额整除小面额(100/50/20/10/5/1),"每次取最大面额"= 最优。✅ 正确
排除法:无(判断题)。混淆点:面额不整除时该贪心可能失败(H3/P2)。
关联 · 找零贪心的条件(H3):整除关系是前提。
单选题:活动安排问题(每个活动有开始、结束时间,选最多个互不重叠的活动),正确的贪心策略是?
考点:活动安排的策略(B2)。
解析:选最多不相交活动:按结束时间升序,能选就选——结束早的活动给后面留出更多时间。正确答案 A。
排除法:B(按开始时间)会选到"早开始长活动"挤掉多个(H2);C(短活动优先)同样有反例;D 方向反。
关联 · 区间调度按右端点(C1):右端点 = 结束时间。
单选题: 个人排队接水、每人用时不同,要使总等待时间最小,接水顺序应该是?
考点:排队接水的顺序(B3)。
解析:短任务先做,等待时间总和最小(交换论证:相邻两人交换,短的在前总等待更小)。正确答案 A。
排除法:B 方向反;C 显然错误(顺序影响等待);D 无依据。
关联 · 排队接水等待和(K2): 人总等待 。
单选题:物品可以分割的背包问题(部分背包),贪心策略是?
考点:部分背包的策略(B4)。
解析:物品可分割 → 单位价值(价值/重量)高的先拿,可分割保证"不会浪费容量"。正确答案 A。
排除法:B 忽略重量;C 忽略价值;D 无依据。
关联 · 零一背包的反例(E6):不可分割时此策略失效。
判断题:合并果子(每次合并两堆、代价为两堆之和,求最小总代价):每次合并当前最小的两堆——本质是构建哈夫曼树。
考点:合并果子的策略(B5)。
解析:每次合并最小两堆 = 哈夫曼树构建,总代价最小。✅ 正确
排除法:无(判断题)。混淆点:合并顺序不同代价不同(先合并的大堆会被重复计费)。
关联 · 合并果子与哈夫曼树(H4):总代价 = WPL。
判断题:均分纸牌:从左到右扫描,把每堆与平均值的差"传递"给下一堆,移动次数 = 差值不为 0 的堆数。
考点:均分纸牌的传递(B6)。
解析:从左到右把"当前堆与平均值的差"传递下去,差值归零处无需移动。✅ 正确
排除法:无(判断题)。混淆点:移动次数 = 差值非零的堆数(最后一堆差值必为 0)。
关联 · 均分纸牌次数(M6):
{9,8,17,6}需 3 次。
单选题:删数问题(删掉 个数字使剩下的数最小),贪心策略是?
考点:删数问题的策略(B7)。
解析:删 位使最小:从左到右找第一个"峰"(当前位 > 后一位),删掉峰顶——高位变小收益最大。正确答案 A。
排除法:B/C 只看数字大小不看位置;D 方向反。
关联 · 删数问题输出(K6):
1432219删 3 位 →1219。
判断题:选最多不相交区间:按右端点升序排序,依次选"开始时间 上一个选中区间右端点"的区间——该贪心正确。
考点:区间调度按右端点(C1)。
解析:按右端点升序 + 能选就选(开始 上次结束)→ 最多不相交区间。✅ 正确
排除法:无(判断题)。混淆点:右端点排序后第一个区间必在最优解中(贪心选择性质)。
关联 · 活动安排计数(J1):代码版输出 2。
单选题:用最少的点覆盖所有区间(每个区间至少含一个点),贪心策略是?
考点:区间选点(C2)。
解析:按右端点排序,当前区间未被覆盖就选它的右端点——右端点"压线"能覆盖最多后续区间。正确答案 A。
排除法:B 选左端点可能覆盖不到靠右的区间;C 中点无依据;D 无依据。
关联 · 区间选点数(J3):4 个区间只需 2 个点。
单选题:用最少的区间覆盖给定线段 ,贪心策略是?
考点:区间覆盖(C3)。
解析:覆盖线段:按左端点排序,在"左端点 ≤ 当前覆盖点"的区间中选右端点最远的。正确答案 A。
排除法:B/C/D 都不能保证"每步把覆盖点推得最远"。
关联 · 区间覆盖数(J4):覆盖 需 5 个区间。
单选题:安排所有活动所需的最少教室数,正确做法是?
考点:最少教室数(C4)。
解析:按开始时间排序 + 数组维护各教室最早结束时间:有"结束 ≤ 开始"的教室就复用最早结束的那间,否则新开。正确答案 A。
排除法:B 是"选最多活动"的策略,与教室数无关;C/D 无依据。
关联 · 最少教室数(J5):代码版输出 3。
判断题:区间分组(把区间分成最少的组、组内互不重叠)= 最少教室问题,解法完全相同。
考点:区间分组(C5)。
解析:区间分组(组内互不重叠、组数最少)= 最少教室问题,同解。✅ 正确
排除法:无(判断题)。混淆点:同一个问题两种说法——分教室、分会议室、分生产线。
关联 · 最少教室数(C4):同一模型。
判断题:大多数贪心先排序(按某种键)再扫描——排序是贪心的标准预处理步骤。
考点:排序是贪心的预处理(C6)。
解析:排序让"当前最优"可以一眼看到(最小/最大/最早结束),是贪心的标准第一步。✅ 正确
排除法:无(判断题)。混淆点:排序键选错,贪心就错(H2/P1)。
关联 · 先排序再贪心(D1):套路的第一步。
判断题:区间类贪心套路:明确排序键(左端点或右端点)→ 扫描维护当前状态 → 每步做贪心选择。
考点:区间贪心的套路(C7)。
解析:区间类三步:定排序键(左/右端点)→ 扫描维护状态 → 每步贪心选择。✅ 正确
排除法:无(判断题)。混淆点:不同问题排序键不同——调度/选点按右端点、覆盖按左端点。
关联 · 区间调度按右端点(C1):套路的实例。
判断题:先排序再贪心是常见套路——区间安排、排队接水、部分背包都遵循它。
考点:先排序再贪心(D1)。
解析:区间安排、排队接水、部分背包都是"排序 + 贪心"。✅ 正确
排除法:无(判断题)。混淆点:也有不用排序的贪心(最大子段和、跳跃游戏)。
关联 · 排序是贪心的预处理(C6):排序是为了让贪心可行。
判断题:每次取当前最大或最小(如合并果子取最小两堆、部分背包取最大单价)是贪心最常见的形态。
考点:最值贪心(D2)。
解析:每次取当前最大/最小(合并果子取最小两堆、部分背包取最大单价)是最常见形态。✅ 正确
排除法:无(判断题)。混淆点:"每次取最值"不总正确(合并果子必须每次取最小的两堆,P3 展示了漏一步排序的后果)。
关联 · 每次选最大(I3):最值贪心的代码。
判断题:读贪心题先找"排序键"——题目的限制条件里通常藏着贪心的排序依据(活动按结束时间、背包按单位价值、排队按用时),找到排序键,贪心就成了一半。
考点:从限制条件找排序键(D3)。
解析:贪心题的排序键通常藏在限制条件里:活动安排 → 结束时间;部分背包 → 单位价值;排队接水 → 用时。✅ 正确
排除法:无(判断题)。混淆点:排序键选错,贪心就错(H2 同款教训)。
关联 · 先排序再贪心(D1):找到排序键之后的动作就是排序。
判断题:证明贪心正确性的常用方法:交换论证——把最优解中与贪心不同的相邻选择交换,证明交换后不更差,从而最优解可改成贪心解。
考点:交换论证(D4)。
解析:把最优解逐步"交换"成贪心解、每步不更差 → 贪心最优。✅ 正确
排除法:无(判断题)。混淆点:排队接水"相邻交换"是最经典的交换论证。
关联 · 交换论证证明(F3):与本题是同一个方法。
判断题:拿不准贪心是否正确时,用枚举/暴力对拍验证:小数据下贪心结果与暴力求出的最优解一致,才敢把贪心用在大数据上。
考点:对拍验证贪心(D5)。
解析:小数据下把贪心结果与暴力枚举的最优解对比,一致才敢用——验证贪心的实战手段。✅ 正确
排除法:无(判断题)。混淆点:对拍只能"发现反例",不能"证明正确"(F1~F4 的证明才是严格保证)。
关联 · 用反例验证贪心(A6):对拍就是自动找反例。
单选题:典型贪心(排序 + 线性扫描)的时间复杂度是?
考点:贪心的复杂度(D6)。
解析:排序 + 扫描 → 总 。正确答案 A。
排除法:B 是排序未优化;C/D 是枚举/回溯的量级。
关联 · 贪心与枚举(E2):复杂度是贪心的最大优势。
判断题:当"当前最优"与"后续最优"互相冲突(选了眼前好的会堵死后面的好选择)时,贪心容易失效。
考点:贪心失效的信号(D7)。
解析:眼前最优会堵死后路(选了 A 就不能选更优的 B)→ 贪心易失效。✅ 正确
排除法:无(判断题)。混淆点:0/1 背包就是典型——高单价小物品占容量。
关联 · 贪心缺乏全局观(H1):失效的根源。
判断题:动态规划尝试所有可能的选择、记录每个状态的最优;贪心每步只锁定一个选择——贪心更快,但只对具有贪心选择性质的问题正确。
考点:贪心与动态规划(E1)。
解析:DP 枚举所有选择、记录每个状态最优;贪心每步锁定一个——快但要求贪心选择性质。✅ 正确
排除法:无(判断题)。混淆点:能用贪心的问题通常也能 DP(更慢),反过来不成立。
关联 · 零一背包的反例(E6):贪心失效、必须 DP 的例子。
单选题:同样的问题枚举需要指数时间,若问题具有贪心性质,贪心通常只需?
考点:贪心与枚举(E2)。
解析:指数级枚举 → 贪心 甚至 ,相差几个数量级。正确答案 A。
排除法:B 是暴力枚举的优化版;C/D 是枚举复杂度。
关联 · 贪心的复杂度(D6):排序主导。
判断题:分治把问题拆成独立的子问题分别解决再合并;贪心是顺序地做一连串局部选择——两者思路不同,少数问题(如哈夫曼树)两者都沾边。
考点:贪心与分治(E3)。
解析:分治拆独立子问题再合并;贪心顺序做局部选择——思路不同,哈夫曼树两者都沾边(分治+贪心)。✅ 正确
排除法:无(判断题)。混淆点:别把"每次取最小"当成分治——那是贪心。
关联 · 合并果子与哈夫曼树(H4):贪心 + 分治的交叉点。
判断题:回溯穷举所有可能(指数级但保证正确);贪心只走一条路(快但可能错)——拿不准贪心是否成立时,小数据用回溯/枚举验证。
考点:贪心与回溯(E4)。
解析:回溯穷举(慢而全)、贪心单路(快而险)——不确定贪心时小数据用回溯验证。✅ 正确
排除法:无(判断题)。混淆点:竞赛常规操作: 小对拍, 大贪心。
关联 · 怀疑贪心的信号(E5): 多半不是贪心。
判断题:题目没有明显的贪心性质、且 很小(如 )时,别急着贪心——多半是枚举、回溯或动态规划。
考点:怀疑贪心的信号(E5)。
解析:无明显的贪心性质 + 小 → 通常是枚举/回溯/DP,别硬贪。✅ 正确
排除法:无(判断题)。混淆点: 大 + 可排序扫描 → 才像贪心(F6)。
关联 · 数据范围暗示贪心(F6):数据范围是选题线索。
单选题:物品不可分割的 0/1 背包为什么不能用"按单位价值贪心"?
考点:零一背包的反例(E6)。
解析:不可分割时容量可能被"高单价小物品"占掉,装不下"性价比稍低但更大"的物品 → 次优。正确答案 A。
排除法:B/C 不是原因;D 错——反例见 K5/P5。
关联 · 零一背包贪心结果(K5):贪心 160 vs 最优 220。
判断题:贪心正确性证明的两块拼图:贪心选择性质(第一步选某个元素不亏)+ 最优子结构(选完后剩余子问题的最优解拼出全局最优)。
考点:贪心证明的结构(F1)。
解析:贪心选择性质(第一步选择必属某最优解)+ 最优子结构(剩余子问题最优)。✅ 正确
排除法:无(判断题)。混淆点:两块拼图缺一不可。
关联 · 贪心选择性质(A3):第一块拼图。
判断题:反证法:假设贪心解不是最优,则最优解的某一步与贪心选择不同,据此推出矛盾——贪心证明的常用骨架。
考点:反证法证明(F2)。
解析:假设贪心解非最优 → 最优解某步与贪心不同 → 推出矛盾。✅ 正确
排除法:无(判断题)。混淆点:活动安排的经典证明就靠反证。
关联 · 交换论证证明(F3):另一常用骨架。
判断题:交换论证:把最优解中"与贪心不同的部分"逐步交换成贪心的选择,证明每次交换结果不更差。
考点:交换论证证明(F3)。
解析:把最优解中与贪心不同的部分换成贪心选择,每次不更差。✅ 正确
排除法:无(判断题)。混淆点:排队接水"相邻交换"即此法的实例。
关联 · 交换论证(D4):方法同源。
判断题:数学归纳法也能证明贪心:归纳假设"前 步贪心选择正确",证明第 步也正确。
考点:归纳法证明(F4)。
解析:归纳假设前 步贪心正确 → 证第 步也正确 → 全部正确。✅ 正确
排除法:无(判断题)。混淆点:三种证明(反证/交换/归纳)选最顺手的即可。
关联 · 贪心证明的结构(F1):无论哪种证明都针对两块拼图。
判断题:一个反例就能否定贪心——贪心失效的判据是"找得到反例"。
考点:反例否定贪心(F5)。
解析:一个反例即否定——找反例比证明更容易,是实战中的第一道防线。✅ 正确
排除法:无(判断题)。混淆点:证明难、找反例易——所以竞赛里"感觉能贪"要先打表验证。
关联 · 用反例验证贪心(A6):验证手段。
判断题:数据范围 很大(如 、)且"排序 + 线性扫描"可解,通常暗示贪心或排序贪心。
考点:数据范围暗示贪心(F6)。
解析: 且排序+扫描可解 → 大概率贪心/排序贪心( 会超时)。✅ 正确
排除法:无(判断题)。混淆点: 小则可能是 DP/回溯(E5)——范围反推算法。
关联 · 怀疑贪心的信号(E5):范围小→别贪。
单选题:手电筒过河问题( 人过桥、速度不同、每次最多 2 人、手电筒必须送回),贪心策略是?
考点:过河问题(G1)。
大纲注:本细节在 NOI 2025 大纲中未明确列出,属贪心法的经典应用。
解析:最快的两人负责送手电筒:两个最慢的结伴过、快者往返——每轮送走两个最慢的。正确答案 A。
排除法:B 浪费(最慢的人单独走更慢);C/D 无依据。
关联 · 过河最少时间(N1):
{1,2,5,10}需 17。
单选题:一条数轴上有若干点,要选一个点建仓库,使仓库到所有点的距离之和最小。贪心策略是?
考点:货仓选址的策略(G2)。
解析:数轴上选一点使距离和最小 → 建在中位数处(排序后第 个点)。正确答案 A。
排除法:B(平均值)只在特殊情形等于最优;C/D 显然不是"到各点距离和最小"。
关联 · 货仓选址的距离(L3):代码版输出 6。
判断题:"每个区间至少种一棵树、求最少树数"就是区间选点问题:按右端点排序、每次选右端点。
考点:种树问题(G3)。
解析:"每个区间至少一棵树" = 区间选点:按右端点排序选右端点。✅ 正确
排除法:无(判断题)。混淆点:与 J3 同一模型,换了个生活场景。
关联 · 种树最少棵数(N3):代码版输出 2。
判断题:两个窗口排队接水:贪心每次把下一个人分配给"当前累计时间更小(更早空闲)"的窗口。
考点:双窗口排队(G4)。
解析:每人分配给"当前累计时间更小"的窗口(负载均衡贪心)。✅ 正确
排除法:无(判断题)。混淆点:更多窗口的扩展用数组维护各窗口时间。
关联 · 双窗口排队(K4):代码版总耗时 9。
判断题:把若干数字拼接成最小的数:不能按数值大小排序,要用拼接比较器(a + b < b + a)排序——如 3 和 32 应排成 323 而不是 332。
考点:拼接最小数(G5)。
解析:排序键是拼接比较 a+b < b+a(如 3 与 32:323 < 332,32 在前)——按数值排序会错。✅ 正确
排除法:无(判断题)。混淆点:321 32 3 的正确顺序是 321323。
关联 · 拼接最小数(M2):比较器代码。
单选题:跳跃游戏(每个位置最多能向前跳 a[i] 步,判断能否到达终点)的贪心维护的是?
考点:跳跃游戏(G6)。
解析:维护"当前能到达的最远位置",能覆盖终点即可达——不必试每条路径。正确答案 A。
排除法:B 不一定最优;C 无关;D 是指数级回溯。
关联 · 跳跃能否到达(M5):
{3,2,1,0,4}输出 NO。
单选题:"贪心只顾眼前最优、缺乏全局规划"的最典型后果是?
考点:贪心缺乏全局观(H1)。
解析:只顾眼前的后果:对 0/1 背包这类问题得到次优解(贪了高单价小物品,错过更优组合)。正确答案 A。
排除法:B 是"有贪心性质"时;C 过于绝对;D 无关。
关联 · 零一背包的反例(E6):次优解的具体实例。
单选题:活动安排若按开始时间升序贪心,会?
考点:排序键选错(H2)。
解析:活动安排按开始时间排 → 早开始的长活动挤掉后面多个活动 → 非最优。正确答案 A。
排除法:B/C 错误;D——两个排序键不等价。
关联 · 活动按开始时间排错(P1):代码实证 cnt=1。
单选题:找零贪心(每次取最大面额)成立的常见条件是?
考点:找零贪心的条件(H3)。
解析:面额成倍数关系(大整除小)时贪心成立;否则可能失败(如面额 5/3 找 7 分:贪心剩 2 分)。正确答案 A。
排除法:B 错——有反例;C/D 不是关键条件。
关联 · 面额不可整除(P2):
5/3面额找 7 分的实证。
判断题:合并果子 = 构建哈夫曼树:最小总合并代价 = 哈夫曼树的带权路径长度(WPL)。
考点:合并果子与哈夫曼树(H4)。
解析:每次合并最小两堆构建的正是哈夫曼树,总代价 = 叶子权 × 深度之和 = WPL。✅ 正确
排除法:无(判断题)。混淆点:WPL 越小 → 大的堆合并次数越少 → 总代价越小。
关联 · 哈夫曼的带权路径(L4):
{2,3,5,7}的 WPL = 32。
判断题:以下结论全部正确——"贪心不一定对、需要贪心选择性质;区间调度按右端点排序;0/1 背包贪心会错、部分背包贪心正确;合并果子每次合并最小的两堆"。
考点:贪心综合判断(H5)。
解析:四句全部正确:贪心需要贪心选择性质;区间调度按右端点;0/1 背包贪心错、部分背包对;合并果子每次合并最小的两堆。✅ 正确
排除法:无(判断题)。混淆点:这套结论是本章骨架,逐条对照前几组题目。
关联 · 贪心基本概念(A1):本章各组概念的总结。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int coins[4] = {25, 10, 5, 1}; // 美分面额(1 元 = 100 分) 05 int n = 4, money = 63, cnt = 0; 06 for (int i = 0; i < n; i++) { 07 cnt += money / coins[i]; // 尽量用当前最大面额 08 money %= coins[i]; 09 } 10 cout << cnt; 11 return 0; 12}
单选题:程序输出是?
考点:找零钱的张数(I1)。
解析:,共 枚。正确答案 A。
实现要点:找零框架 = 面额从大到小,cnt += money / coins[i]、money %= coins[i]。手算:从最大面额开始整除、取余。
排除法:B(5)漏数一枚 1 分;C(7)多数;D(4)只数了 25 分和 10 分。
关联 · 找零钱的贪心(B1):最大面额优先。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int coins[4] = {25, 10, 5, 1}; 05 int money = 47; 06 for (int i = 0; i < 4; i++) 07 while (money >= coins[i]) { 08 cout << coins[i] << " "; // 输出找出的每一枚硬币 09 money -= coins[i]; 10 } 11 return 0; 12}
单选题:程序输出是?
考点:找零钱的过程(I2)。
解析: → 输出 25 10 10 1 1。正确答案 A。
实现要点:过程版 = 每枚硬币用 while 循环输出一枚减一次。手算:从大到小逐个"吐出"硬币。
排除法:B(25 25)加起来 50 超了;C 多用了 5 分;D 有 20 分面额(数组里没有)。
关联 · 找零钱的张数(I1):计数版与过程版同源。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {3, 1, 4, 1, 5, 9}; 05 int k = 3, s = 0; // 选 3 个最大的数求和 06 for (int t = 0; t < k; t++) { 07 int p = t; 08 for (int i = t + 1; i < 6; i++) 09 if (a[i] > a[p]) p = i; // 找当前最大的 10 swap(a[t], a[p]); 11 s += a[t]; // 贪心:每次取最大 12 } 13 cout << s; 14 return 0; 15}
单选题:程序输出是?
考点:每次选最大(I3)。
解析:每次选当前最大:。正确答案 A。
实现要点:最值贪心 = 每轮找 [t, n-1] 最大值换到前面(选择排序的单轮操作)。手算:圈出 9、5、4。
排除法:B(15)是 ;C(14)是 ;D(9)只选了一个。
关联 · 最值贪心(D2):贪心的最常见形态。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {3, 1, 4, 1, 5, 9}; 05 sort(a, a + 6, greater<int>()); // 降序排列 06 int s = 0; 07 for (int i = 0; i < 2; i++) s += a[i]; // 取前两个最大的 08 cout << s; 09 return 0; 10}
单选题:程序输出是?
考点:排序后取最大(I4)。
解析:降序后前两个 。正确答案 A。
实现要点:排序 + 取前缀 = 静态最值贪心的标准写法(比 I3 的逐轮选择更简洁)。手算:降序 9 5 4 3 1 1。
排除法:B(15)是 ;C(13)无依据;D(18)是前三个之和。
关联 · 先排序再贪心(D1):排序预处理。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {-2, 1, -3, 4, -1, 2}; 05 int cur = 0, best = 0; 06 for (int i = 0; i < 6; i++) { 07 cur += a[i]; 08 if (cur < 0) cur = 0; // 贪心:和为负就重新开始 09 best = max(best, cur); 10 } 11 cout << best; // 最大子段和 12 return 0; 13}
单选题:程序输出是?
考点:最大子段和(I5)。
解析:Kadane: 为负就清零重新开始,最大子段和 。正确答案 A。
实现要点:Kadane 框架 = cur += a[i];cur < 0 时 cur = 0;best = max(best, cur)。手算:逐项累加,见负清零。
排除法:B(6)是全正数的最大和误解;C(4)漏了后面的段;D(7)无依据。
关联 · 最大子段和进阶(N6):同款算法的 7 元素版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {1, 5, 2, 4, 3}; 05 int l = 0, r = 4; 06 while (l <= r) { 07 if (a[l] < a[r]) { cout << a[l] << " "; l++; } // 每次取两端较小者 08 else { cout << a[r] << " "; r--; } 09 } 10 return 0; 11}
单选题:程序输出是?
考点:两端取较小(I6)。
解析:1 < 3 取 1;5 > 3 取 3;5 > 4 取 4;5 > 2 取 2;剩 5 → 1 3 4 2 5。正确答案 A。
实现要点:双指针 + 每次取两端较小者(贪心)。手算:左右指针逐步靠拢,比较两端值。
排除法:B 是排序结果(贪心不排序);C 是逆序;D 是原数组。
关联 · 最值贪心(D2):双端取小的变体。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int coins[3] = {25, 10, 1}; 05 int money = 41, cnt = 0; 06 for (int i = 0; i < 3; i++) { 07 cnt += money / coins[i]; 08 money %= coins[i]; 09 } 10 cout << cnt; 11 return 0; 12}
单选题:程序输出是?
考点:贪心与枚举同题(I7)。
解析:,共 枚。正确答案 A。
实现要点:同题用贪心 代替枚举所有组合。手算:与 I1 同法。
排除法:B(5)漏数 1 分;C(6)无依据;D(7)无依据。
关联 · 贪心与枚举(E2):复杂度对比的实例。
01#include <bits/stdc++.h> 02using namespace std; 03struct Act { int s, e; }; // 开始、结束时间 04int main() { 05 Act a[5] = {{1,4},{3,5},{0,6},{5,7},{3,8}}; 06 sort(a, a + 5, [](Act x, Act y){ return x.e < y.e; }); // 按结束时间排序 07 int cnt = 0, last = -1; 08 for (int i = 0; i < 5; i++) 09 if (a[i].s >= last) { cnt++; last = a[i].e; } // 能选就选 10 cout << cnt; 11 return 0; 12}
单选题:程序输出是?
考点:活动安排计数(J1)。
解析:按结束时间排序后选 、 两个活动。正确答案 A。
实现要点:活动安排框架 = 按右端点排序 + s >= last 才选。手算:先排序,再从头扫描、能接就接。
排除法:B(3)是"选 3 个"的乐观误解( 与 重叠);C/D 更不可能。
关联 · 活动安排的策略(B2):策略的代码实现。
01#include <bits/stdc++.h> 02using namespace std; 03struct Act { int id, s, e; }; 04int main() { 05 Act a[5] = {{1,1,4},{2,3,5},{3,0,6},{4,5,7},{5,3,8}}; 06 sort(a, a + 5, [](Act x, Act y){ return x.e < y.e; }); 07 int last = -1; 08 for (int i = 0; i < 5; i++) 09 if (a[i].s >= last) { cout << a[i].id << " "; last = a[i].e; } 10 return 0; 11}
单选题:程序输出是?
考点:选中的活动编号(J2)。
解析:排序后依次选编号 1(1~4)、4(5~7)→ 1 4。正确答案 A。
实现要点:带上编号排序、输出选中编号。手算:先按结束时间排序得 1,2,3,4,5 的次序,再贪心挑。
排除法:B 多选了 2(与 1 重叠);C 多选 3;D 首选的 2 不是最早结束。
关联 · 活动安排计数(J1):编号版。
01#include <bits/stdc++.h> 02using namespace std; 03struct Seg { int l, r; }; 04int main() { 05 Seg s[4] = {{1,3},{2,5},{4,6},{5,8}}; 06 sort(s, s + 4, [](Seg x, Seg y){ return x.r < y.r; }); 07 int cnt = 0, pos = -1; 08 for (int i = 0; i < 4; i++) 09 if (s[i].l > pos) { cnt++; pos = s[i].r; } // 未覆盖就选右端点 10 cout << cnt; 11 return 0; 12}
单选题:程序输出是?
考点:区间选点数(J3)。
解析:选 的右端点 3(覆盖 、),再选 的右端点 6(覆盖 、)→ 2 个点。正确答案 A。
实现要点:区间选点 = 按右端点排序,l > pos 时选该区间右端点。手算:每选一个点,看它覆盖了哪些后续区间。
排除法:B(4)是一区间一点;C(3)多数一个;D(1)漏数。
关联 · 区间选点(C2):策略的代码实现。
01#include <bits/stdc++.h> 02using namespace std; 03struct Seg { int l, r; }; 04int main() { 05 Seg s[5] = {{0,3},{2,5},{4,7},{6,9},{8,10}}; 06 sort(s, s + 5, [](Seg x, Seg y){ return x.l < y.l; }); 07 int R = 10, cur = 0, cnt = 0, i = 0; 08 while (cur < R) { // 覆盖 [0, 10] 09 int far = cur; 10 while (i < 5 && s[i].l <= cur) { far = max(far, s[i].r); i++; } 11 if (far == cur) { cnt = -1; break; } // 出现缺口,无法覆盖 12 cur = far; cnt++; // 选右端点最远的区间 13 } 14 cout << cnt; 15 return 0; 16}
单选题:程序输出是?
考点:区间覆盖数(J4)。
解析:覆盖 :,共 5 个区间。正确答案 A。
实现要点:区间覆盖 = 按左端点排序,每步在"左端点 ≤ cur"中选右端点最远者。手算:看当前覆盖点,选能推得最远的区间。
排除法:B(4)漏掉最后一截 ;C/D 无依据。
关联 · 区间覆盖(C3):策略的代码实现。
01#include <bits/stdc++.h> 02using namespace std; 03struct Act { int s, e; }; 04int main() { 05 Act a[4] = {{1,4},{2,5},{3,6},{4,7}}; 06 sort(a, a + 4, [](Act x, Act y){ return x.s < y.s; }); // 按开始时间 07 int end[4] = {0}, rooms = 0; // 各教室最早结束时间 08 for (int i = 0; i < 4; i++) { 09 int t = -1; 10 for (int j = 0; j < rooms; j++) // 找最早结束且可复用的教室 11 if (end[j] <= a[i].s && (t == -1 || end[j] < end[t])) t = j; 12 if (t == -1) { t = rooms; rooms++; } // 没有可复用的,新开一间 13 end[t] = a[i].e; 14 } 15 cout << rooms; 16 return 0; 17}
单选题:程序输出是?
考点:最少教室数(J5)。
解析:活动 开教室 0; 无可用开教室 1; 开教室 2; 复用教室 0 → 3 间。正确答案 A。
实现要点:按开始时间排序 + end[] 数组维护各教室最早结束时间,找"结束 ≤ 开始"的最早那间复用,没有就新开。手算:画时间轴,同一时刻最多重叠数 = 教室数。
排除法:B(4)每活动一间;C(2)低估重叠;D 无依据。
关联 · 最少教室数(C4):概念版与代码版同解。
01#include <bits/stdc++.h> 02using namespace std; 03struct Act { int id, s, e; }; 04int main() { 05 Act a[4] = {{1,6,8},{2,1,4},{3,3,5},{4,0,6}}; 06 sort(a, a + 4, [](Act x, Act y){ return x.e < y.e; }); // 按结束时间排序 07 for (int i = 0; i < 4; i++) cout << a[i].id << " "; 08 return 0; 09}
单选题:程序输出是?
考点:按右端点排序输出(J6)。
解析:结束时间排序:2(4)、3(5)、4(6)、1(8)→ 2 3 4 1。正确答案 A。
实现要点:排序比较器 x.e < y.e 决定输出次序。手算:列出各活动结束时间,从小到大排。
排除法:B 是按开始时间逆序;C 是 1 排错;D 是原顺序。
关联 · 区间调度按右端点(C1):排序键的意义。
01#include <bits/stdc++.h> 02using namespace std; 03struct Seg { int l, r; }; 04int main() { 05 Seg s[5] = {{1,3},{2,6},{8,10},{15,18},{16,17}}; 06 sort(s, s + 5, [](Seg x, Seg y){ return x.l < y.l; }); 07 int l = s[0].l, r = s[0].r, cnt = 1; 08 for (int i = 1; i < 5; i++) { 09 if (s[i].l <= r) r = max(r, s[i].r); // 重叠,合并 10 else { cnt++; l = s[i].l; r = s[i].r; } // 新的一段 11 } 12 cout << cnt; // 合并后区间个数 13 return 0; 14}
单选题:程序输出是?
考点:区间合并计数(J7)。
解析:合并后 、、 共 3 段。正确答案 A。
实现要点:按左端点排序,重叠(l <= r)就扩右端,否则开新段。手算:逐段看是否与前一段重叠。
排除法:B(5)没合并;C(2)合并过度;D(4)漏合并 。
关联 · 区间贪心的套路(C7):排序 + 扫描的又一实例。
01#include <bits/stdc++.h> 02using namespace std; 03struct Item { int w, v; }; // 重量、价值 04int main() { 05 Item it[3] = {{10,60},{20,100},{30,120}}; 06 double cap = 50, ans = 0; // 背包容量 50,物品可分割 07 sort(it, it + 3, [](Item x, Item y){ 08 return (double)x.v / x.w > (double)y.v / y.w; }); // 按单位价值排序 09 for (int i = 0; i < 3; i++) { 10 if (cap >= it[i].w) { ans += it[i].v; cap -= it[i].w; } 11 else { ans += (double)it[i].v * cap / it[i].w; break; } // 取一部分 12 } 13 cout << (int)ans; 14 return 0; 15}
单选题:程序输出是?
考点:部分背包最大价值(K1)。
解析:单位价值 6、5、4:拿 10(60)+ 20(100)+ 30 中的 20 重量(80)→ 240。正确答案 A。
实现要点:部分背包 = 按单位价值排序 + 能装全装、装不下按比例取。手算:先算单位价值,再按序装。
排除法:B(220)是 0/1 背包的最优值;C/D 无依据。
关联 · 部分背包的策略(B4):策略的代码实现。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int t[5] = {3, 1, 4, 1, 5}; // 每人接水时间 05 int n = 5; 06 sort(t, t + n); // 短的先接 07 long long sum = 0, wait = 0; 08 for (int i = 0; i < n; i++) { 09 wait += sum; // 轮到的人要等前面所有人 10 sum += t[i]; 11 } 12 cout << wait; // 总等待时间 13 return 0; 14}
单选题:程序输出是?
考点:排队接水等待和(K2)。
解析:排序 ,等待 。正确答案 A。
实现要点:等待和 = 每个人等前面所有人的时间:wait += sum(sum 为已接完累计)。手算:逐人累加。
排除法:B(14)漏加最后一个等待;C(20)顺序没排序;D 无依据。
关联 · 排队接水的顺序(B3):短的先接。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int t[4] = {2, 5, 3, 1}; 05 int n = 4; 06 sort(t, t + n); 07 long long sum = 0, total = 0; 08 for (int i = 0; i < n; i++) { 09 sum += t[i]; 10 total += sum; // 每人"从开始到接完"的总时间 11 } 12 cout << total; 13 return 0; 14}
单选题:程序输出是?
考点:排队接水总时间(K3)。
解析:排序 ,总时间 。正确答案 A。
实现要点:总时间 = 每人"等待 + 自己接水"之和 = 前缀和之和。手算:。
排除法:B(17)是等待和(不含自己);C/D 无依据。
关联 · 排队接水等待和(K2):总时间 = 等待和 + 各人用时。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int t[5] = {3, 1, 4, 1, 5}; 05 int n = 5; 06 sort(t, t + n); // 1 1 3 4 5 07 int w1 = 0, w2 = 0; // 两个窗口的累计时间 08 for (int i = 0; i < n; i++) { 09 if (w1 <= w2) w1 += t[i]; // 分配给更早空闲的窗口 10 else w2 += t[i]; 11 } 12 cout << max(w1, w2); // 全部接完的时间 13 return 0; 14}
单选题:程序输出是?
考点:双窗口排队(K4)。
解析:分配:1→A、1→B、3→A、4→B、5→A → A 用 9、B 用 5 → 总耗时 9。正确答案 A。
实现要点:双窗口 = 每次分配给累计时间更小的窗口。手算:维护两个累计值,逐个分配。
排除法:B(7)漏加最后 5;C(8)分配次序错;D(14)是单窗口总时间。
关联 · 双窗口排队(G4):负载均衡贪心。
01#include <bits/stdc++.h> 02using namespace std; 03struct Item { int w, v; }; 04int main() { 05 Item it[3] = {{10,60},{20,100},{30,120}}; 06 int cap = 50, greedy = 0; // 0/1 背包(不可分割),容量 50 07 sort(it, it + 3, [](Item x, Item y){ 08 return (double)x.v / x.w > (double)y.v / y.w; }); 09 for (int i = 0; i < 3; i++) 10 if (cap >= it[i].w) { greedy += it[i].v; cap -= it[i].w; } 11 cout << greedy; // 贪心结果(最优应为 220) 12 return 0; 13}
单选题:程序输出是?
考点:零一背包贪心结果(K5)。
解析:贪心取 重量、价值 160;最优取 重量、价值 220——贪心次优。正确答案 A。
实现要点:0/1 背包贪心 = 按单位价值排序但装不下就跳过(不可分割)。手算:对比"贪心结果"与"最优组合"。
排除法:B(220)是最优值(DP 才能得到);C/D 无依据。
关联 · 零一背包的反例(E6):贪心失效的实证。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 string s = "1432219"; // 删 3 个数字使剩下最小 05 int k = 3; 06 for (int t = 0; t < k; t++) { 07 int pos = 0; 08 while (pos + 1 < s.size() && s[pos] <= s[pos + 1]) pos++; // 找第一个峰 09 s.erase(pos, 1); // 删掉峰顶 10 } 11 cout << s; 12 return 0; 13}
单选题:程序输出是?
考点:删数问题输出(K6)。
解析:1432219 删 3 位:删 4 → 132219;删 3 → 12219;删 2 → 1219。正确答案 A。
实现要点:找第一个"峰"(,即 s[pos] <= s[pos+1] 不成立处)删除。手算:从左到右找下降处,删掉下降前的高位。
排除法:B(1221)删错了位;C/D 无依据。
关联 · 删数问题的策略(B7):删峰顶。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {1, 2, 3, 4, 5}; // 五堆果子的重量 05 int n = 5, ans = 0; 06 sort(a, a + n); // 先排序:最小的两堆在最前面 07 for (int t = 1; t < n; t++) { // 合并 n-1 次 08 int s = a[t - 1] + a[t]; // 取当前最小的两堆 09 ans += s; 10 a[t] = s; // 新堆放回 11 sort(a + t, a + n); // 重新排序剩余部分 12 } 13 cout << ans; 14 return 0; 15}
单选题:程序输出是?
考点:合并果子总代价(L1)。
解析:合并 、、、,总代价 。正确答案 A。
实现要点:排序模拟版合并果子 = 排序 → 每轮取最小两堆(a[t-1]+a[t])→ 新堆放回 a[t] → sort(a+t, a+n) 重排剩余。手算:每轮取两个最小数求和,放回后保持有序。
排除法:B(30)漏一次合并;C(36)合并顺序错;D(35)无依据。
关联 · 合并果子的策略(B5):策略的排序模拟实现。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {2, 3, 5, 7}; 05 int n = 4; 06 sort(a, a + n); 07 for (int t = 1; t < n; t++) { 08 int s = a[t - 1] + a[t]; 09 cout << s << " "; // 输出每次合并产生的新堆 10 a[t] = s; 11 sort(a + t, a + n); 12 } 13 return 0; 14}
单选题:程序输出是?
考点:合并果子的过程(L2)。
解析:、、 → 5 10 17。正确答案 A。
实现要点:过程版 = 每轮输出新堆,与 L1 同框架。手算:跟踪数组变化 (每次重排剩余部分)。
排除法:B 第二次合并应是 不是 ;C 次序错;D 次序错。
关联 · 合并果子总代价(L1):过程与总代价同源。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {1, 2, 3, 4, 5}; // 数轴上的 5 个点 05 int n = 5; 06 sort(a, a + n); 07 int mid = a[n / 2]; // 仓库建在中位数处 08 int total = 0; 09 for (int i = 0; i < n; i++) total += abs(a[i] - mid); 10 cout << total; // 到各点距离之和 11 return 0; 12}
单选题:程序输出是?
考点:货仓选址的距离(L3)。
解析:中位数 3,距离和 。正确答案 A。
实现要点:货仓选址 = 排序取中位数 + 距离求和。手算:把点排好序,正中间的点就是最优位置。
排除法:B(4)取错位置;C(8)按平均值算;D(10)无依据。
关联 · 货仓选址的策略(G2):概念题的代码版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int w[4] = {2, 3, 5, 7}; // 叶子权值 05 int n = 4, wpl = 0; 06 sort(w, w + n); 07 for (int t = 1; t < n; t++) { // 每次合并最小的两个 08 int s = w[t - 1] + w[t]; 09 wpl += s; // 合并代价之和 = WPL 10 w[t] = s; 11 sort(w + t, w + n); 12 } 13 cout << wpl; 14 return 0; 15}
单选题:程序输出是?
考点:哈夫曼的带权路径(L4)。
解析:合并 、、,WPL 。正确答案 A。
实现要点:WPL = 所有合并代价之和,排序模拟版与合并果子流程一致。手算:同 L1 的流程。
排除法:B(34)多算;C(30)漏一次;D(28)无依据。
关联 · 合并果子与哈夫曼树(H4):两题同构。
01#include <bits/stdc++.h> 02using namespace std; 03struct Item { int w, v; }; 04int main() { 05 Item it[3] = {{10,60},{20,100},{30,120}}; 06 double cap = 50; // 背包容量 50,物品可分割 07 sort(it, it + 3, [](Item x, Item y){ 08 return (double)x.v / x.w > (double)y.v / y.w; }); // 按单位价值排序 09 for (int i = 0; i < 3 && cap > 0; i++) { 10 int take = min((double)it[i].w, cap); // 能装多少装多少 11 cout << take << " "; 12 cap -= take; 13 } 14 return 0; 15}
单选题:程序输出是?
考点:部分背包的过程(L5)。
解析:按单位价值装:装 10、装 20、剩 20 容量装 30 中的 20 → 10 20 20。正确答案 A。
实现要点:过程版部分背包 = 排序后逐件 take = min(w, cap)、cap -= take。手算:单位价值 6/5/4,按序装到容量耗尽。
排除法:B 第三件全装(超容量);C 装反序;D 无依据。
关联 · 部分背包最大价值(K1):过程版与总价值版同源。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {1, 9, 2, 8, 3}; // 数轴上的 5 个点 05 int n = 5; 06 sort(a, a + n); 07 cout << a[n / 2]; // 中位数位置 08 return 0; 09}
单选题:程序输出是?
考点:货仓选址的位置(L6)。
解析:排序后 ,中位数 。正确答案 A。
实现要点:选址位置 = 排序后第 个元素(下标从 0 起)。手算:5 个点取第 3 个。
排除法:B(8)是次大;C(5)是平均值;D(9)是最大值。
关联 · 货仓选址的距离(L3):先定位(L6)再算距离(L3)。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 string s = "178543"; // 删 2 个数字使剩下最小 05 int k = 2; 06 for (int t = 0; t < k; t++) { 07 int pos = 0; 08 while (pos + 1 < s.size() && s[pos] <= s[pos + 1]) pos++; 09 s.erase(pos, 1); 10 } 11 cout << s; 12 return 0; 13}
单选题:程序输出是?
考点:删两个数字(M1)。
解析:178543 删 2 位:删 8( 峰顶)→ 17543;删 7()→ 1543。正确答案 A。
实现要点:同 K6 的删峰框架。手算:找第一个"前大后小"处删前位,重复 k 次。
排除法:B(1743)第二处删错;C(1541)无依据;D(1430)无依据。
关联 · 删数问题输出(K6):同框架不同数据。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 string a[3] = {"3", "32", "321"}; 05 sort(a, a + 3, [](string x, string y){ return x + y < y + x; }); // 拼接比较器 06 for (int i = 0; i < 3; i++) cout << a[i]; 07 return 0; 08}
单选题:程序输出是?
考点:拼接最小数(M2)。
解析:比较器排序:321 < 32 < 3(按 x+y < y+x)→ 拼接 321323。正确答案 A。
实现要点:拼接比较器 return x + y < y + x。手算:两两比较"AB 与 BA 谁小",用比较器排序。
排除法:B(332321)是最大拼接;C(321332)是 32 与 3 次序错;D 无依据。
关联 · 拼接最小数(G5):比较器的代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 string a[3] = {"3", "32", "321"}; 05 sort(a, a + 3, [](string x, string y){ return x + y > y + x; }); // 反向比较器 06 for (int i = 0; i < 3; i++) cout << a[i]; 07 return 0; 08}
单选题:程序输出是?
考点:拼接最大数(M3)。
解析:反向比较器:3 > 32 > 321 → 拼接 332321。正确答案 A。
实现要点:最大拼接 = 比较器 x+y > y+x。手算:与 M2 镜像。
排除法:B 是最小拼接;C/D 次序错。
关联 · 拼接最小数(M2):镜像题。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {2, 3, 1, 1, 4}; // 每个位置最多向前跳的步数 05 int n = 5, steps = 0, cur = 0, far = 0; 06 for (int i = 0; i < n - 1; i++) { 07 far = max(far, i + a[i]); // 贪心:维护能到达的最远位置 08 if (i == cur) { steps++; cur = far; } // 到达当前覆盖边界,步数加一 09 } 10 cout << steps; 11 return 0; 12}
单选题:程序输出是?
考点:跳跃最少步数(M4)。
解析:{2,3,1,1,4}:第 1 步覆盖到下标 2,第 2 步从覆盖内跳到终点 → 2 步。正确答案 A。
实现要点:最少步数 = 维护 far 最远覆盖 + 到达当前覆盖边界(i == cur)时步数 +1。手算:逐层画"当前步能覆盖的范围"。
排除法:B(3)多算一步;C(1)一步到不了;D 无依据。
关联 · 跳跃游戏(G6):最远覆盖的贪心。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {3, 2, 1, 0, 4}; 05 int n = 5, far = 0; 06 for (int i = 0; i < n; i++) { 07 if (i > far) break; // 当前位置到不了 08 far = max(far, i + a[i]); 09 } 10 cout << (far >= n - 1 ? "YES" : "NO"); 11 return 0; 12}
单选题:程序输出是?
考点:跳跃能否到达(M5)。
解析:最远只能到下标 3(a[3]=0 卡死),到不了下标 4 → NO。正确答案 A。
实现要点:可达性 = 扫描时 i > far 即断(当前位置不可达),最后看 far >= n-1。手算:逐步更新最远距离。
排除法:B 是可达时的输出;C/D 是中间值不是输出。
关联 · 跳跃最少步数(M4):可达性是最少步数的前提。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {9, 8, 17, 6}; // 四堆纸牌 05 int n = 4, sum = 0; 06 for (int i = 0; i < n; i++) sum += a[i]; 07 int avg = sum / n, cnt = 0, diff = 0; 08 for (int i = 0; i < n; i++) { 09 diff += a[i] - avg; // 把差值"传递"给下一堆 10 if (diff != 0) cnt++; // 差值为 0 说明不用移动 11 } 12 cout << cnt; 13 return 0; 14}
单选题:程序输出是?
考点:均分纸牌次数(M6)。
解析:平均 10:差值 ,前三次非零 → 3 次移动。正确答案 A。
实现要点:均分纸牌 = diff += a[i] - avg,diff != 0 就计数。手算:把差值一路传递,归零处停。
排除法:B(4)把最后归零那堆也数了;C/D 无依据。
关联 · 均分纸牌的传递(B6):传递法代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int t[4] = {1, 2, 5, 10}; // 4 人过桥时间(手电筒每次必须送回) 05 sort(t, t + 4); 06 int n = 4, ans = 0; 07 while (n > 3) { // 每次送走最慢的两人 08 int way1 = t[0] + 2 * t[1] + t[n - 1]; // 最快两人来回带 09 int way2 = 2 * t[0] + t[n - 2] + t[n - 1]; // 最快的人单独往返 10 ans += min(way1, way2); 11 n -= 2; 12 } 13 if (n == 3) ans += t[0] + t[1] + t[2]; 14 else if (n == 2) ans += t[1]; 15 else ans += t[0]; 16 cout << ans; 17 return 0; 18}
单选题:程序输出是?
考点:过河最少时间(N1)。
大纲注:本细节在 NOI 2025 大纲中未明确列出,属贪心法的经典应用。
解析:{1,2,5,10}:way1 优于 way2 ,送走 5、10 后剩 1、2 → 再过 2 秒,总 17。正确答案 A。
实现要点:过河框架 = 每轮两种方案取小(快者带最慢两个 vs 两个最慢结伴),最后收尾按剩余人数。手算:模拟每轮的手电筒往返。
排除法:B(19)方案选错;C(15)漏了最后的 2 秒;D 无依据。
关联 · 过河问题(G1):策略的代码实现。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {-2, 1, -3, 4, -1, 2}; 05 int cur = 0, best = 0, L = 0, R = 0, tmp = 0; 06 for (int i = 0; i < 6; i++) { 07 cur += a[i]; 08 if (cur < 0) { cur = 0; tmp = i + 1; } // 和为负,重新开始 09 else if (cur > best) { best = cur; L = tmp; R = i; } // 记录更优区间 10 } 11 cout << best << " " << L << " " << R; // 最大和与区间左右端点 12 return 0; 13}
单选题:程序输出是?
考点:最大子段和的区间(N2)。
解析:最大子段和 ,区间 → 5 3 5。正确答案 A。
实现要点:Kadane 记录区间版 = tmp 记当前段起点、cur 变负时 tmp = i + 1 重新开始、cur > best 时更新 L/R。手算:逐项累加,见负重启。
排除法:B 区间右端少 1;C 漏了最后一项的更新;D 起点错。
关联 · 最大子段和(I5):同算法的区间记录版。
01#include <bits/stdc++.h> 02using namespace std; 03struct Seg { int l, r; }; // 每个区间至少种一棵树 04int main() { 05 Seg s[4] = {{1,3},{2,5},{4,6},{5,8}}; 06 sort(s, s + 4, [](Seg x, Seg y){ return x.r < y.r; }); 07 int cnt = 0, pos = -1; 08 for (int i = 0; i < 4; i++) 09 if (s[i].l > pos) { cnt++; pos = s[i].r; } // 区间选点 10 cout << cnt; 11 return 0; 12}
单选题:程序输出是?
考点:种树最少棵数(N3)。
解析:同 J3:选 3 和 6 两个位置 → 2 棵。正确答案 A。
实现要点:种树 = 区间选点框架。手算:按右端点排序后逐个覆盖。
排除法:B(4)每区间一棵;C/D 无依据。
关联 · 种树问题(G3):区间选点的生活版。
01#include <bits/stdc++.h> 02using namespace std; 03struct Seg { int l, r; }; 04int main() { 05 Seg s[4] = {{1,3},{2,5},{4,6},{5,8}}; 06 sort(s, s + 4, [](Seg x, Seg y){ return x.r < y.r; }); 07 int pos = -1; 08 for (int i = 0; i < 4; i++) 09 if (s[i].l > pos) { pos = s[i].r; cout << pos << " "; } // 输出所选点 10 return 0; 11}
单选题:程序输出是?
考点:区间选点的位置(N4)。
解析:按右端点排序: 选 3(覆盖 ), 选 6(覆盖 )→ 3 6。正确答案 A。
实现要点:区间选点输出版 = J3 框架 + 输出所选右端点。手算:每选一个点,看它覆盖哪些后续区间。
排除法:B(3 5)第二个点选错;C(1 4)选的是左端点;D(6 8)无依据。
关联 · 区间选点数(J3):计数版与位置版同框架。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int t[5] = {3, 1, 4, 1, 5}; // 每人接水时间 05 pair<int,int> p[5]; // {用时, 编号} 06 for (int i = 0; i < 5; i++) p[i] = {t[i], i + 1}; 07 sort(p, p + 5); // 默认先比用时、再比编号 08 for (int i = 0; i < 5; i++) cout << p[i].second << " "; // 输出接水顺序 09 return 0; 10}
单选题:程序输出是?
考点:排队接水的顺序编号(N5)。
解析:用时排序(同用时按编号): → 编号 2 4 1 3 5。正确答案 A。
实现要点:pair<int,int> 默认先比 first 再比 second——{用时, 编号} 排序即得接水顺序。手算:排序后读编号列。
排除法:B 是原编号序;C 是逆序;D 无依据。
关联 · 排队接水等待和(K2):顺序确定后的等待和计算。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[7] = {3, -5, 2, -1, 4, -2, 3}; 05 int cur = 0, best = 0; 06 for (int i = 0; i < 7; i++) { 07 cur += a[i]; 08 if (cur < 0) cur = 0; 09 best = max(best, cur); 10 } 11 cout << best; 12 return 0; 13}
单选题:程序输出是?
考点:最大子段和进阶(N6)。
解析:最大子段和 。正确答案 A。
实现要点:同 I5 的 Kadane。手算:。
排除法:B(5)漏了最后的 3;C(3)只算了前段;D 无依据。
关联 · 最大子段和(I5):同算法不同数据。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int coins[4] = {25, 10, 5, 1}; 05 int money = 87, cnt = 0; 06 for (int i = 0; i < 4; i++) { 07 cnt += ______; // 当前面额能用几张 08 money %= coins[i]; 09 } 10 cout << cnt; 11 return 0; 12}
单选题:横线处应填入?
考点:补全找零钱(O1)。
解析:当前面额的张数 = money / coins[i]。运行: → 6 枚。正确答案 A。
实现要点:整除取张数、取余更新余额——两行是固定搭配。
排除法:B 是余额;C 除反了;D 无依据。
关联 · 找零钱的张数(I1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03struct Act { int s, e; }; 04int main() { 05 Act a[5] = {{1,4},{3,5},{0,6},{5,7},{3,8}}; 06 sort(a, a + 5, [](Act x, Act y){ return x.e < y.e; }); 07 int cnt = 0, last = -1; 08 for (int i = 0; i < 5; i++) 09 if (______) { cnt++; last = a[i].e; } // 当前活动能选 10 cout << cnt; 11 return 0; 12}
单选题:横线处应填入?
考点:补全活动安排(O2)。
解析:当前活动开始 上次结束才能选,填 a[i].s >= last。运行输出 2。正确答案 A。
实现要点:能选就选 = s >= last(等号允许首尾相接)。手算:按右端点排好序后逐个判断。
排除法:B 条件反;C 比较了结束时间;D 恒假。
关联 · 活动安排计数(J1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int t[5] = {3, 1, 4, 1, 5}; 05 int n = 5; 06 sort(t, t + n, ______); // 短的先接 07 long long wait = 0, sum = 0; 08 for (int i = 0; i < n; i++) { wait += sum; sum += t[i]; } 09 cout << wait; 10 return 0; 11}
单选题:横线处应填入?
考点:补全排队接水(O3)。
解析:短者先接 = 升序,填 less<int>()。运行输出 17。正确答案 A。
实现要点:升序比较器 less<int>()(或省略第三个参数)。手算:排序后逐人累计等待。
排除法:B 是降序(长者先接,结果更差);C 不是合法比较器;D 无依据。
关联 · 排队接水等待和(K2):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {1, 2, 3, 4, 5}; 05 int n = 5, ans = 0; 06 sort(a, a + n); 07 for (int t = 1; t < n; t++) { 08 int s = a[t - 1] + a[t]; 09 ans += s; 10 a[t] = ______; // 新堆放回数组 11 sort(a + t, a + n); 12 } 13 cout << ans; 14 return 0; 15}
单选题:横线处应填入?
考点:补全合并果子(O4)。
解析:新堆放回数组,填 s。运行输出 33。正确答案 A。
实现要点:排序模拟版三步:取最小两堆求和 → a[t] = s 放回 → sort(a+t, a+n) 重排剩余。手算:跟踪每轮数组状态。
排除法:B(a[t-1])把旧堆放回;C(0)丢失新堆;D 无依据。
关联 · 合并果子忘重新排序(P3):漏第三步的后果。
01#include <bits/stdc++.h> 02using namespace std; 03struct Seg { int l, r; }; 04int main() { 05 Seg s[4] = {{1,3},{2,5},{4,6},{5,8}}; 06 sort(s, s + 4, [](Seg x, Seg y){ return x.r < y.r; }); 07 int cnt = 0, pos = -1; 08 for (int i = 0; i < 4; i++) 09 if (s[i].l > pos) { cnt++; pos = ______; } // 选当前区间的右端点 10 cout << cnt; 11 return 0; 12}
单选题:横线处应填入?
考点:补全区间选点(O5)。
解析:当前区间未覆盖时选它的右端点,填 s[i].r。运行输出 2。正确答案 A。
实现要点:选右端点才能"压线"覆盖最多后续区间。手算:跟踪已选点覆盖的范围。
排除法:B 选左端点覆盖效果差;C 是区间长度;D 是右端点 +1(位置错)。
关联 · 区间选点数(J3):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 string s = "1432219"; 05 int k = 3; 06 for (int t = 0; t < k; t++) { 07 int pos = 0; 08 while (pos + 1 < s.size() && ______) pos++; // 找第一个"峰" 09 s.erase(pos, 1); 10 } 11 cout << s; 12 return 0; 13}
单选题:横线处应填入?
考点:补全删数问题(O6)。
解析:找第一个峰 = 一直向右直到出现下降,条件 s[pos] <= s[pos + 1]。运行输出 1219。正确答案 A。
实现要点:上升(或持平)就继续走,遇到下降停下——该位置就是峰顶。手算:扫描数字串找"前大后小"。
排除法:B 找的是谷;C 用严格小于会停在相等处;D 是找下降本身。
关联 · 删数问题输出(K6):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03struct Act { int s, e; }; 04int main() { 05 Act a[5] = {{1,4},{3,5},{0,6},{5,7},{3,8}}; 06 sort(a, a + 5, [](Act x, Act y){ return x.s < y.s; }); // 错误:按开始时间 07 int cnt = 0, last = -1; 08 for (int i = 0; i < 5; i++) 09 if (a[i].s >= last) { cnt++; last = a[i].e; } 10 cout << cnt; // 正确做法(按结束时间)应为 2 11 return 0; 12}
单选题:程序输出是?
考点:活动按开始时间排错(P1)。
解析:按开始时间排:先选 ,后面全部重叠 → 只选 1 个(正确做法 2 个)。正确答案 A。
实现要点:排序键决定贪心成败:活动安排必须按结束时间排。手算:对比两个排序键的结果。
排除法:B(2)是按右端点的正确结果;C/D 无依据。
关联 · 排序键选错(H2):概念题的代码实证。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int coins[2] = {5, 3}; // 面额只有 5 分和 3 分(没有 1 分) 05 int money = 7, cnt = 0; 06 for (int i = 0; i < 2; i++) { 07 cnt += money / coins[i]; 08 money %= coins[i]; 09 } 10 cout << cnt << " " << money; // 张数和剩余金额 11 return 0; 12}
单选题:程序输出是?
考点:面额不可整除(P2)。
解析:7 分用 5/3 面额:1 枚 5 分后剩 2 分,3 分面额用不上 → 输出 1 2(找不开)。正确答案 A。
实现要点:贪心逐面额处理后,剩余非零 = 找不开——面额不成倍数时贪心失败(H3)。手算:按面额逐个整除取余。
排除法:B(2 0)假设 3 分也能整除;C/D 无依据。
关联 · 找零贪心的条件(H3):整除关系是前提。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {1, 2, 3, 4, 5}; 05 int n = 5, ans = 0; 06 sort(a, a + n); 07 for (int t = 1; t < n; t++) { 08 int s = a[t - 1] + a[t]; 09 ans += s; 10 a[t] = s; 11 // 错误:合并后忘了 sort(a + t, a + n) 12 } 13 cout << ans; // 正确结果应为 33 14 return 0; 15}
单选题:程序输出是?
考点:合并果子忘重新排序(P3)。
解析:漏了 sort(a+t, a+n):、、、 → 34(正确 33)。正确答案 A。
实现要点:合并后必须重排剩余部分,否则"最小的两堆"可能不在前面。手算:跟踪数组逐轮变化 。
排除法:B(33)是正确结果;C/D 无依据。
关联 · 补全合并果子(O4):正确写法对照。
01#include <bits/stdc++.h> 02using namespace std; 03struct Act { int s, e; }; 04int main() { 05 Act a[3] = {{1,3},{3,5},{5,7}}; // 首尾相接的活动可以连续选 06 sort(a, a + 3, [](Act x, Act y){ return x.e < y.e; }); 07 int cnt = 0, last = -1; 08 for (int i = 0; i < 3; i++) 09 if (a[i].s > last) { cnt++; last = a[i].e; } // 错误:应为 >= 10 cout << cnt; // 正确结果应为 3 11 return 0; 12}
单选题:程序输出是?
考点:区间边界丢等号(P4)。
解析:(3,5) 开始恰等于上次结束 3,条件 s > last(应为 >=)把它漏掉 → 2 个(正确 3 个)。正确答案 A。
实现要点:首尾相接(前一个结束 = 后一个开始)可以连选,条件必须带等号。手算:边界值逐一核对。
排除法:B(3)是带等号的正确结果;C/D 无依据。
关联 · 补全活动安排(O2):
>=的边界细节。
判断题:0/1 背包按单位价值贪心会得到次优解——例如容量 、物品 、、 时,贪心取 得价值 ,而最优是取 得价值 。
考点:零一背包贪心反例(P5)。
解析:容量 50:贪心按单位价值取 (价值 160);最优取 (价值 220)——贪心次优。✅ 正确
排除法:无(判断题)。混淆点:物品不可分割时"性价比排序"不再是正确策略(E6)。
关联 · 零一背包贪心结果(K5):同例的代码版。
判断题:以下结论全部正确——"活动安排按右端点排序、合并果子每次合并最小的两堆、部分背包贪心正确而 0/1 背包贪心错误、删数问题删第一个峰"。
考点:贪心代码综合判断(P6)。
解析:四句全部正确:活动安排按右端点、合并果子每次合并最小的两堆、部分背包贪心对而 0/1 贪心错、删数删第一个峰。✅ 正确
排除法:无(判断题)。混淆点:这些是本章代码组的结论汇总,逐条对照各组题目。
关联 · 贪心综合判断(H5):概念组与代码组的双总结。