判断题:递归 = 函数在定义中直接或间接调用它自身。
考点:递归的定义(A1)。
解析:递归 = 函数直接(自己调自己)或间接(A 调 B、B 调 A)调用自身。✅ 正确
排除法:无(判断题)。混淆点:递归必须有出口(A2),否则无限递归。
关联 · 递归的两要素(A2):出口 + 递归关系,缺一不可。
判断题:递归的两要素:① 边界条件(出口——最小情形直接返回结果);② 递归关系(把问题化归为规模更小的同类问题)。
考点:递归的两要素(A2)。
解析:① 边界条件 = 最小情形的直接答案(如 );② 递归关系 = 把问题化归为规模更小的同类问题。✅ 正确
排除法:无(判断题)。混淆点:边界写在递归调用之前,先判断再递归(G1)。
关联 · 递归出口写在前面(G1):出口先行,防死递归。
判断题:递归执行时每一层调用都记录在系统调用栈里:先层层进入(问题变小),再层层返回(把结果传回去);栈最深时的高度就是递归深度。
考点:递归的执行过程(A3)。
解析:每层调用入栈(保存现场),先层层深入直到出口,再层层返回、把结果带回。✅ 正确
排除法:无(判断题)。混淆点:递归深度 = 栈中同时存在的最大层数(J5)。
关联 · 递归深度统计(J5):进入加一、返回减一。
判断题:任何递归都可以改写为循环(递推),任何循环也可以改写为递归——两者的表达能力是等价的。
考点:递归与循环的转换(A4)。
解析:递归与循环表达能力等价:递归改循环就是递推(正向填表),循环改递归就是加参数化规模。✅ 正确
排除法:无(判断题)。混淆点:等价的是"能力",性能上递推通常更快(无栈帧开销)。
关联 · 递推与递归的方向(C2):递归自顶向下、递推自底向上。
单选题:递归层数过深(例如对 规模直接层层递归)会导致?
考点:递归深度与栈溢出(A5)。
解析:递归每层占一段栈空间, 层远超默认栈容量 → 栈溢出崩溃。正确答案 A。
排除法:B/C 是幻想;D 反而更慢(A6)。
关联 · 递归的调用开销(A6):深度过大时改用递推(G4)。
判断题:递归的每一层调用都要占用栈帧(保存参数、局部变量、返回地址),常数开销比等价的循环大。
考点:递归的调用开销(A6)。
解析:每次调用要保存参数、局部变量、返回地址(栈帧),常数开销大于循环。✅ 正确
排除法:无(判断题)。混淆点:开销大不代表不能用——代码清晰时仍优先递归。
关联 · 递归与递推的选择(G4):深度可控用递归,否则递推。
判断题:阶乘的递归定义:,边界 。
考点:阶乘的递归定义(B1)。
解析:, 是出口——最经典的递归入门。✅ 正确
排除法:无(判断题)。混淆点:出口选 保证 也有定义。
关联 · 阶乘递归输出(I1):。
单选题:斐波那契数列 ,。 的值是?
考点:斐波那契的递推式(B2)。
解析:——。正确答案 A。
排除法:B()是 ;C()是 ;D()是 。
关联 · 斐波那契递归的重复计算(B3):直接递归的代价。
判断题:直接递归求 时,同一个子问题会被重复计算很多遍(例如 被反复调用),时间复杂度是指数级 。
考点:斐波那契递归的重复计算(B3)。
解析: 的递归树里同一子问题出现多次( 被反复调用),总调用次数指数级 → 。✅ 正确
排除法:无(判断题)。混淆点:不是"递归慢",是"重复计算"慢——递推(或把算过的结果存起来)都能解决。
关联 · 指数爆炸的原因(H2):重复子问题是祸根。
单选题: 个盘子的汉诺塔问题,最少移动次数是?
考点:汉诺塔的移动次数(B4)。
解析: 个盘最少 次移动(,每加一个盘翻倍再加 1)。正确答案 A。
排除法:B/C 是多项式量级,与"翻倍"规律不符;D()无依据。
关联 · 汉诺塔的递推式(B5):。
单选题:汉诺塔移动次数 满足的递推式是?
考点:汉诺塔的递推式(B5)。
解析:先把上面 个盘移走( 步)→ 移最大盘(1 步)→ 再把 个盘移回来( 步):。正确答案 A。
排除法:B 是等差数列;C 漏了"移最大盘"的 1 步;D 无依据。
关联 · 汉诺塔次数递推(N6):。
判断题:辗转相除法求最大公约数:gcd(a, b) = gcd(b, a % b),当 b == 0 时返回 a——结构天然适合递归实现。
考点:辗转相除求最大公约数(B6)。
解析:gcd(a, b) = gcd(b, a % b),b == 0 时返回 a——参数不断变小、结构相同,天然递归。✅ 正确
排除法:无(判断题)。混淆点:a % b 一定小于 b,参数严格递减,必达出口。
关联 · 递归求最大公约数(I6):
gcd(48, 36) = 12。
判断题:递归求数组和:sum(l, r) = a[l] + sum(l+1, r),边界 l > r 时返回 0——把问题分解成"第一个元素 + 剩余部分的和"。
考点:递归求数组和(B7)。
解析:sum(l, r) = a[l] + sum(l+1, r),l > r 返回 0——"第一个元素 + 其余部分",规模每次减 1。✅ 正确
排除法:无(判断题)。混淆点:这类"线性递归"深度 ,求和用循环更简洁——递归是教学示范。
关联 · 递归求 1 到 n 的和(I3):同款结构的整数版。
判断题:递推 = 从已知的初始值出发,按递推公式从前往后一项一项算出后续各项。
考点:递推的定义(C1)。
解析:递推 = 已知初始值,按公式从前往后逐项计算(正向填表)。✅ 正确
排除法:无(判断题)。混淆点:递推不需要函数调用栈,空间常为 或滚动 。
关联 · 递推的循环实现(C7):循环 + 数组填表。
判断题:递归是自顶向下(大问题拆成子问题),递推是自底向上(从小问题算到大问题)——方向相反。
考点:递推与递归的方向(C2)。
解析:递归从目标出发向下拆(自顶向下),递推从初始值出发向上算(自底向上)。✅ 正确
排除法:无(判断题)。混淆点:两者结果相同、复杂度可同可异(C4)。
关联 · 递推的滚动变量(C5):递推常配滚动变量省空间。
单选题:递推的三要素是?
考点:递推的三要素(C3)。
解析:初始值(如 )、递推公式(如 )、目标项(要算到哪)。正确答案 A。
排除法:B 是实现工具不是要素;C 是所有程序的通用结构;D 是其他章节的概念。
关联 · 递推初值写错(H4):初始值是三要素中最易错的。
单选题:求斐波那契第 项:直接递归约需 级别次调用,改用递推(循环填表)只需?
考点:递推与递归的复杂度对比(C4)。
解析:递推每个状态算一次, 只需约 次迭代;直接递归约 次调用。正确答案 A。
排除法:B()是 的误解;C 是全排列量级;D 低估了线性递推()。
关联 · 斐波那契递推输出(K1): 的填表过程。
判断题:递推不必存整个数组:如斐波那契只需两个变量滚动更新,空间复杂度从 降到 。
考点:递推的滚动变量(C5)。
解析:只保留递推需要的最近几项(斐波那契用两个变量滚动),空间从 降到 。✅ 正确
排除法:无(判断题)。混淆点:滚动变量只省空间、不省时间(每个状态仍要算一次)。
关联 · 递推取模(K6):滚动 + 取模的标准写法。
单选题:爬楼梯,每次走 级或 级。,、。上 级楼梯共有几种走法?
考点:爬楼梯问题(C6)。
解析:、、、、——上 5 级共 种。正确答案 A。
排除法:B()是 ;C()是 ;D()是 。
关联 · 爬楼梯递推输出(K2): 的代码。
判断题:递推通常用循环 + 数组(或滚动变量)实现,按规模从小到大"填表"。
考点:递推的循环实现(C7)。
解析:循环变量从小到大,每轮用已算出的项填新项;空间可滚动优化到 。✅ 正确
排除法:无(判断题)。混淆点:滚动变量只保留最近两项(K6)。
关联 · 递推取模(K6):滚动 + 取模的标准写法。
判断题:回溯 = 尝试一个选择 → 递归继续走 → 走不通或走完就撤销该选择(恢复现场)→ 再试下一个选择。
考点:回溯的定义(D1)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:回溯 = 尝试 → 递归 → 撤销(恢复现场)→ 试下一个选择,穷举所有可能。✅ 正确
排除法:无(判断题)。混淆点:"撤销"是回溯区别于普通递归的标志(P3 忘撤销的教训)。
关联 · 回溯三部曲(D2):选择、递归、撤销。
单选题:回溯算法的标准三部曲是?
考点:回溯三部曲(D2)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:选择(打标记/记录)→ 递归(深入下一层)→ 撤销(清标记/恢复现场)。正确答案 A。
排除法:B(排序→查找→合并)与回溯无关;C 是栈的操作;D 无依据。
关联 · 全排列回溯计数(M1):三部曲的标准应用。
判断题:回溯的本质是深度优先搜索(DFS):沿一条路径走到底,走不通就退回上一步换条路。
考点:回溯与深度优先搜索(D3)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:回溯沿一条路径走到底、再退回换路——正是 DFS 的搜索方式。✅ 正确
排除法:无(判断题)。混淆点:回溯强调"状态恢复",DFS 强调"遍历顺序",同一枚硬币的两面。
关联 · 回溯的复杂度(D7):DFS 树的大小决定复杂度。
单选题: 个不同元素的全排列共有几种?
考点:全排列的数量(D4)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析: 个不同元素的全排列 = ; 时 。正确答案 A。
排除法:B 是 ;C 是 ;D 是 的误解。
关联 · 全排列的个数(M2): 时 。
单选题: 个元素的集合共有多少个子集(含空集)?
考点:子集的数量(D5)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:每个元素"选/不选"两种选择,独立相乘 → ; 时 。正确答案 A。
排除法:B()是排列数;C 是元素个数;D 无依据。
关联 · 子集回溯计数(M3):选/不选两个分支的代码。
判断题:回溯 = 枚举所有方案的通用框架:排列、组合、子集都能用同一个"选择 → 递归 → 撤销"模板写出来。
考点:回溯与枚举的关系(D6)。
解析:回溯 = 枚举所有方案的通用框架:排列、组合、子集都是"选择 → 递归 → 撤销"同一个模板。✅ 正确
排除法:无(判断题)。混淆点:与第 11 章枚举相比,回溯多了"递归深入 + 状态恢复",适合方案数随深度增长的问题。
关联 · 回溯三部曲(D2):模板的三步。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
判断题:回溯的复杂度通常是指数级:全排列 、子集 ——数据规模一大,就容易超时。
考点:回溯的复杂度(D7)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:回溯要遍历解空间:排列 、子集 ——指数级,规模一大就容易超时。✅ 正确
排除法:无(判断题)。混淆点: 稍大(排列 )回溯就撑不住,此时要换思路(数学计数、递推等)。
关联 · 回溯与枚举的关系(D6):回溯的适用边界。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
判断题:差分数组 记录相邻元素的差;对区间 每个数加 ,只需 d[l] += x、d[r+1] -= x 两处标记。
考点:差分的思想(E1)。
解析: 记录相邻差;区间 加 只需 d[l] += x、d[r+1] -= x——"头尾标记、前缀和还原"。✅ 正确
排除法:无(判断题)。混淆点:标记位置错一位( 与 )区间就错——这是差分最高频的坑。
关联 · 前缀和(第 6 章 C 组):差分是前缀和的逆运算。
判断题:差分与前缀和互为逆运算:对差分数组做前缀和还原出原数组,对前缀和数组做差分也还原出原数组。
考点:差分与前缀和的关系(E2)。
解析:差分与前缀和互为逆运算:前缀和数组的差分 = 原数组,差分数组的前缀和 = 原数组。✅ 正确
排除法:无(判断题)。混淆点:两者方向相反——前缀和"累加",差分"做差"。
关联 · 差分的思想(E1):逆运算关系是差分的根基。
判断题:"多次区间整体加、最后统一查询"的场景用差分:每次修改 、最后还原 。
考点:差分的应用场景(E3)。
解析:"多次区间加、最后统一查询"用差分:每次修改 、还原 。✅ 正确
排除法:无(判断题)。混淆点:修改与查询交替进行的场景差分不适用(F5)。
关联 · 差分适用场景(F5):适用边界的补充。
判断题:倍增 = 每次翻倍地跳():把 的逐步推进压缩成 步。
考点:倍增的思想(E4)。
解析:每次翻倍地跳(): 的逐步推进压缩成 步。✅ 正确
排除法:无(判断题)。混淆点:倍增要求"能一次跳过 步"——跳不动就减半再试。
关联 · 翻倍需要的次数(L3):。
判断题:快速幂把指数按二进制拆分( 次方),乘法次数从 降到 ——倍增思想的典型应用。
考点:快速幂与倍增(E5)。
解析:快速幂把指数按二进制拆成 次方,乘法次数 ——倍增思想的典型应用。✅ 正确
排除法:无(判断题)。混淆点:拆分的依据是"任何整数都能写成 2 的幂之和"(F7 的二进制拆分)。
关联 · 快速幂(N3):代码版输出 。
判断题:倍增类算法的复杂度是 ——因为翻倍次数就是对数级。
考点:倍增的复杂度(E6)。
解析:翻倍次数 = 对数级:。✅ 正确
排除法:无(判断题)。混淆点:倍增类算法通常每步 或 预处理,总体仍远快于逐次推进。
关联 · 倍增的思想(E4):复杂度的来源。
判断题:差分数组的构造:,()——一遍 扫描即可。
考点:差分数组的构造(F1)。
解析:,——一遍 扫描构造。✅ 正确
排除法:无(判断题)。混淆点:下标从 1 起、 比 多开一位( 要能存)。
关联 · 差分数组构造输出(N1):代码版。
单选题:对区间 每个数加 ,差分操作是?
考点:区间加的差分标记(F2)。
解析:区间 加 = d[l] += x + d[r+1] -= x——头加尾减、两处标记。正确答案 A。
排除法:B 漏了"区间外抵消"的尾标记;C 方向反;D 缺尾标记区间会一直加到结尾。
关联 · 差分区间加输出(L1):标记 + 还原的完整代码。
判断题:对差分数组求前缀和即还原原数组——差分标记只影响区间内、区间外自动抵消。
考点:差分还原成原数组(F3)。
解析:对差分数组求前缀和 = 还原原数组; 处的反向标记让区间外自动抵消。✅ 正确
排除法:无(判断题)。混淆点:还原后的 是"所有经过 的标记之和"。
关联 · 差分还原输出(L2):还原过程的代码。
单选题: 次区间加 + 最后 次还原查询,差分的总复杂度是?
考点:差分的复杂度(F4)。
解析: 次修改 + 一次还原 → 。正确答案 A。
排除法:B 是暴力法(每次修改扫区间);C/D 无依据。
关联 · 差分与暴力对比(F6): 规模下的差距。
判断题:差分适合"修改集中、查询靠后";若修改与查询频繁交替,应改用其他更合适的数据结构。
考点:差分适用场景(F5)。
解析:修改集中、查询靠后 → 差分;修改查询频繁交替 → 差分不适用(每次查询都要 还原)。✅ 正确
排除法:无(判断题)。混淆点:交替场景需其他数据结构(提高级内容),CSP-J 只考"先改后查"。
关联 · 差分的应用场景(E3):适用条件的两个说法。
单选题: 时,暴力区间加约 次操作会超时,差分约需?
考点:差分与暴力对比(F6)。
解析::暴力 超时;差分 级别。正确答案 A。
排除法:B 是暴力量级;C/D 无依据。
关联 · 差分的复杂度(F4):量级差的来源。
判断题:先差分做区间修改、再前缀和还原——两者结合是处理区间批量操作的标准套路。
考点:差分与前缀和综合(F7)。
解析:先差分做区间修改、再前缀和还原——区间批量操作的标准套路。✅ 正确
排除法:无(判断题)。混淆点:套路顺序不能反:先改(差分标记)后查(前缀和还原)。
关联 · 差分与前缀和综合输出(L5):综合代码版。
判断题:递归函数必须先写出口(边界条件)再写递归调用——否则会无限递归下去。
考点:递归出口写在前面(G1)。
解析:先判断边界、再写递归调用——顺序反了会先递归、永远到不了出口。✅ 正确
排除法:无(判断题)。混淆点:出口条件要覆盖所有"最小情形"(如 、 都写)。
关联 · 缺少边界条件(H1):没出口 = 死递归。
判断题:递归参数应体现"问题规模在缩小"(如区间端点 l、r 每次收缩),保证每次递归都向出口靠近。
考点:递归参数的设计(G2)。
解析:参数应随递归单调变化、向出口靠近(如区间 l, r 不断收缩、n 不断减小)。✅ 正确
排除法:无(判断题)。混淆点:参数不变化(或变化不向出口靠)就是死循环式递归。
关联 · 递归反转数组(J7):
l+1, r-1双参数收缩。
判断题:递推结果很大时(如斐波那契第 项),每步计算后都对 MOD 取模,可以防止溢出——加减乘运算中"先算再模"与"边算边模"结果一致。
考点:递推中的取模(G3)。
解析:加法/乘法满足 ——每步取模结果一致且防溢出。✅ 正确
排除法:无(判断题)。混淆点:除法没有这个性质(要逆元),CSP-J 阶段递推取模通常只涉及加减乘。
关联 · 递推取模(K6):滚动 + 每步
% MOD。
判断题:递归深度可控(对数级/较浅)时用递归更直观;深度可能过大、或要求常数空间时改用递推。
考点:递归与递推的选择(G4)。
解析:递归直观但耗栈;深度可达 以上、或追求常数时选递推。✅ 正确
排除法:无(判断题)。混淆点:把算过的结果缓存起来是折中——保留递归结构、去掉重复计算。
关联 · 递归深度与栈溢出(A5):深度是选择的关键依据。
判断题:斐波那契第 项约 ,已接近 long long 上限——递推题要先估算结果范围、选对整数类型。
考点:递推结果的增长(G5)。
解析:斐波那契第 90 项约 ,接近 long long 上限()——递推前先估算结果范围选类型。✅ 正确
排除法:无(判断题)。混淆点:需要更大范围时按题目要求取模(G3),不是硬换更大的类型。
关联 · 递推中的取模(G3):超范围的标准处理。
单选题:递归函数缺少边界条件(出口),会发生什么?
考点:缺少边界条件(H1)。
解析:没有出口 → 每层调用又产生调用 → 无限递归 → 栈溢出。正确答案 A。
排除法:B/C 是幻想;D——缺少出口不会"自动停一次"。
关联 · 缺边界的递归(P1):
f(n-1)一路减到负无穷。
单选题:斐波那契直接递归是指数复杂度的根本原因是?
考点:指数爆炸的原因(H2)。
解析: 与 的递归树里子问题大量重叠(同一 被算许多遍)——重复计算是 的根源。正确答案 A。
排除法:B 无依据;C——递归本身不比循环慢一个量级;D 是结果不是原因。
关联 · 斐波那契递归的重复计算(B3):概念题与本题互为表里。
单选题:递归函数里该写 return f(n-1) 却写成 f(n-1)(丢弃了返回值),会导致?
考点:return 的丢失(H3)。
解析:递归结果靠 return 逐层上传,丢一层就断链——上层拿到垃圾值。正确答案 A。
排除法:B 无依据;C——编译器不会自动补;D——能编译(P2 的行为未定义)。
关联 · 丢失 return 的递归(P2):代码实证。
单选题:爬楼梯 、。若把 误写成 ,则按 算出的 会变成?
考点:递推初值写错(H4)。
解析: 错成 1 后:、——初值错一处、后面全错。正确答案 A。
排除法:B()是正确初值的答案;C/D 是中间项。
关联 · 递推初值被覆盖(P4):循环起点写错是同一类错误。
判断题:以下结论全部正确——"递归与循环等价;递推把斐波那契降到 ;回溯本质是 DFS;差分与前缀和互为逆运算"。
考点:递归递推综合判断(H5)。
解析:四句全部正确:递归与循环等价(A4);递推把斐波那契降到 (C4);回溯本质是 DFS(D3);差分与前缀和互为逆运算(E2)。✅ 正确
排除法:无(判断题)。混淆点:这套概念是本章骨架,逐条对照前几组题目。
关联 · 递归基本概念(A1):本章各组概念的总结。
01#include <bits/stdc++.h> 02using namespace std; 03int f(int n) { // 计算 n! 04 if (n == 0) return 1; // 边界 05 return n * f(n - 1); // 递归关系 06} 07int main() { cout << f(5); return 0; }
单选题:程序输出是?
考点:阶乘递归输出(I1)。
解析:。正确答案 A。
实现要点:阶乘框架 = 出口 n == 0 返回 1 + return n * f(n-1)。手算:沿递归链把乘法展开成一条链。
排除法:B(24)是 ;C(5)漏了递归;D(0)是出口值。
关联 · 阶乘的递归定义(B1):概念题的代码实现。
01#include <bits/stdc++.h> 02using namespace std; 03int f(int n) { 04 if (n == 1 || n == 2) return 1; // 边界 05 return f(n - 1) + f(n - 2); // 递推式 06} 07int main() { cout << f(7); return 0; }
单选题:程序输出是?
考点:斐波那契递归输出(I2)。
解析:。正确答案 A。
实现要点:斐波那契递归 = 双出口(n==1 || n==2 返回 1)+ f(n-1) + f(n-2)。手算从小往大列:1, 1, 2, 3, 5, 8, 13。
排除法:B(8)是 ;C(21)是 ;D(7)是参数本身。
关联 · 斐波那契的递推式(B2):递推式即递归关系。
01#include <bits/stdc++.h> 02using namespace std; 03int s(int n) { // 求 1 + 2 + ... + n 04 if (n == 1) return 1; 05 return n + s(n - 1); 06} 07int main() { cout << s(100); return 0; }
单选题:程序输出是?
考点:递归求 1 到 n 的和(I3)。
解析:。正确答案 A。
实现要点:求和框架 = 出口 n == 1 + return n + s(n-1)。手算:展开成 ,或直接套高斯公式核对。
排除法:B(4950)少加 100;C(100)只返回参数;D(5000)按 的误解。
关联 · 递归求数组和(B7):同款结构作用在数组上。
01#include <bits/stdc++.h> 02using namespace std; 03void p(int n) { 04 if (n == 0) return; 05 p(n - 1); // 先递归 06 cout << n << " "; // 返回时才打印 07} 08int main() { p(5); return 0; }
单选题:程序输出是?
考点:递归正序输出(I4)。
解析:先递归后打印 → 最深层()先打印 → 正序 1 2 3 4 5。正确答案 A。
实现要点:打印位置决定顺序:print 在递归之后 = 返回时打印 = 正序;在递归之前 = 进入时打印 = 逆序(I5)。手算:沿递归链看 print 的执行时机。
排除法:B 是逆序(print 在前);C 只打印奇数;D 是每次打印参数。
关联 · 返回时打印的顺序(J2):正序输出 = 返回序。
01#include <bits/stdc++.h> 02using namespace std; 03void p(int n) { 04 if (n == 0) return; 05 cout << n << " "; // 进入时就打印 06 p(n - 1); 07} 08int main() { p(5); return 0; }
单选题:程序输出是?
考点:递归逆序输出(I5)。
解析:先打印后递归 → 最先进入()先打印 → 逆序 5 4 3 2 1。正确答案 A。
实现要点:print 在递归之前 = 进入序(与 I4 镜像)。手算:进入一层打印一次。
排除法:B 是正序;C 打印参数 5 次(没递归);D 打印奇数。
关联 · 进入时打印的顺序(J1):逆序输出 = 进入序。
01#include <bits/stdc++.h> 02using namespace std; 03int g(int a, int b) { // 辗转相除 04 if (b == 0) return a; 05 return g(b, a % b); 06} 07int main() { cout << g(48, 36); return 0; }
单选题:程序输出是?
考点:递归求最大公约数(I6)。
解析:gcd(48, 36) = gcd(36, 12) = gcd(12, 0) = 12。正确答案 A。
实现要点:辗转相除递归 = 出口 b == 0 返回 a + g(b, a % b)。手算:连续取模,直到余数为 0。
排除法:B(6)是 和 的 gcd;C(4)无依据;D(24)是 的约数但不是 gcd。
关联 · 辗转相除求最大公约数(B6):递归结构的经典。
01#include <bits/stdc++.h> 02using namespace std; 03int s(int n) { // 求 1~n 中所有奇数的和 04 if (n == 0) return 0; 05 if (n % 2 == 1) return n + s(n - 1); 06 return s(n - 1); 07} 08int main() { cout << s(10); return 0; }
单选题:程序输出是?
考点:递归求奇数和(I7)。
解析:。正确答案 A。
实现要点:递归框架 = 出口 n == 0 + 分支(奇数加自己、偶数跳过)+ s(n-1)。手算:。
排除法:B(30)是偶数和的误解;C(55)是 总和;D 无依据。
关联 · 递归求 1 到 n 的和(I3):同框架加奇偶判断。
01#include <bits/stdc++.h> 02using namespace std; 03void f(int n) { 04 if (n == 0) return; 05 cout << n << " "; // 进入时打印 06 f(n - 1); 07} 08int main() { f(3); return 0; }
单选题:程序输出是?
考点:进入时打印的顺序(J1)。
解析:进入即打印:f(3) 打 3 → f(2) 打 2 → f(1) 打 1 → f(0) 返回 → 输出 3 2 1。正确答案 A。
实现要点:递归序 = 先序(进入序)。手算:按"进入一层打一层"往下写,遇出口回退。
排除法:B 是返回序;C 无依据;D 多打了 0(f(0) 直接 return 不打印)。
关联 · 递归逆序输出(I5):同一写法。
01#include <bits/stdc++.h> 02using namespace std; 03void f(int n) { 04 if (n == 0) return; 05 f(n - 1); 06 cout << n << " "; // 返回时打印 07} 08int main() { f(3); return 0; }
单选题:程序输出是?
考点:返回时打印的顺序(J2)。
解析:返回才打印:最深层先回、先打 → 1 2 3。正确答案 A。
实现要点:递归序 = 后序(返回序)。手算:一路进到底(不打),从最深处往回逐层打印。
排除法:B 是进入序;C/D 无依据。
关联 · 递归正序输出(I4):同一写法。
01#include <bits/stdc++.h> 02using namespace std; 03void f(int n) { 04 if (n == 0) return; 05 cout << n << " "; // 进入时打印 06 if (n >= 2) f(n - 2); // 左分支 07 f(n - 1); // 右分支 08} 09int main() { f(3); return 0; }
单选题:程序输出是?
考点:递归树的输出(J3)。
解析:f(3) 打 3 → 左 f(1) 打 1 → 右 f(2) 打 2 → 其左 f(0) 返回 → 其右 f(1) 打 1 → 输出 3 1 2 1。正确答案 A。
实现要点:双分支递归 = 深度优先遍历递归树:先走完左子树再走右子树。手算:画树(3 → 左 1 / 右 2 → 左 0 / 右 1),按 DFS 先序读出。
排除法:B 漏了 f(2) 的左子返回前的打印;C 是返回序;D 多打一个 1。
关联 · 回溯与深度优先搜索(D3):递归树遍历 = DFS。
01#include <bits/stdc++.h> 02using namespace std; 03int cnt = 0; 04int f(int n) { 05 cnt++; // 每进入一次计数 06 if (n == 0) return 0; 07 return f(n - 1) + 1; 08} 09int main() { f(5); cout << cnt; return 0; }
单选题:程序输出是?
考点:递归调用次数(J4)。
解析:f(5) → f(4) → f(3) → f(2) → f(1) → f(0),共进入 6 次。正确答案 A。
实现要点:计数 = 在函数入口 cnt++。手算:数递归链上的节点数(含出口那层)。
排除法:B(5)漏了 f(0);C(15)是斐波那契型重复调用;D 无依据。
关联 · 递归调用次数(P5 对照):斐波那契型调用次数指数增长。
01#include <bits/stdc++.h> 02using namespace std; 03int dep = 0, mx = 0; 04void f(int n) { 05 dep++; 06 mx = max(mx, dep); // 记录最大深度 07 if (n == 0) { dep--; return; } 08 f(n - 1); 09 dep--; 10} 11int main() { f(5); cout << mx; return 0; }
单选题:程序输出是?
考点:递归深度统计(J5)。
解析:最深链 f(5) → f(4) → f(3) → f(2) → f(1) → f(0),共 6 层。正确答案 A。
实现要点:深度 = 进入 dep++、离开 dep--,用 mx 记录峰值。手算:递归链上最长的路径长度。
排除法:B(5)漏数出口层;C 少两层;D 多一层。
关联 · 递归的执行过程(A3):深度 = 栈的峰值高度。
01#include <bits/stdc++.h> 02using namespace std; 03void f(int n) { 04 if (n == 0) return; 05 f(n / 2); // 先递归 06 cout << n % 2; // 返回时输出余数 07} 08int main() { f(13); return 0; }
单选题:程序输出是?
考点:递归打印二进制(J6)。
解析::f(13)→f(6)→f(3)→f(1)→f(0),返回时依次打 1 1 0 1 → 1101。正确答案 A。
实现要点:进制转换 = 先递归 f(n/2)、返回时打 n % 2(先高位后低位)。手算:除 2 取余,余数倒着读。
排除法:B(1011)是余数正着读;C(111)漏了 0;D(13)没转换。
关联 · 返回时打印的顺序(J2):后序打印实现"倒读余数"。
01#include <bits/stdc++.h> 02using namespace std; 03int a[6] = {1, 2, 3, 4, 5, 6}; 04void rev(int l, int r) { 05 if (l >= r) return; 06 swap(a[l], a[r]); // 交换两端 07 rev(l + 1, r - 1); // 递归处理中间 08} 09int main() { 10 rev(0, 5); 11 for (int i = 0; i < 6; i++) cout << a[i] << " "; 12 return 0; 13}
单选题:程序输出是?
考点:递归反转数组(J7)。
解析:交换两端、递归中间:1↔6, 2↔5, 3↔4 → 6 5 4 3 2 1。正确答案 A。
实现要点:反转框架 = 出口 l >= r + swap(a[l], a[r]) + rev(l+1, r-1)。手算:两端指针逐步靠拢。
排除法:B 是原数组;C 只换了一次;D 交换次序错。
关联 · 递归参数的设计(G2):双参数收缩的示范。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 long long f[50]; 05 f[1] = f[2] = 1; // 初始值 06 for (int i = 3; i <= 10; i++) 07 f[i] = f[i - 1] + f[i - 2]; // 递推公式(正向填表) 08 cout << f[10]; 09 return 0; 10}
单选题:程序输出是?
考点:斐波那契递推输出(K1)。
解析:正向填表:1, 1, 2, 3, 5, 8, 13, 21, 34, 55 → 。正确答案 A。
实现要点:递推框架 = 初始值 + for 填表。手算:一行行写出数组,直到目标项。
排除法:B(34)是 ;C(89)是 ;D(21)是 。
关联 · 递推的循环实现(C7):填表法的范本。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int f[20]; 05 f[1] = 1; f[2] = 2; // 爬楼梯初始值 06 for (int i = 3; i <= 6; i++) 07 f[i] = f[i - 1] + f[i - 2]; 08 cout << f[6]; 09 return 0; 10}
单选题:程序输出是?
考点:爬楼梯递推输出(K2)。
解析:。正确答案 A。
实现要点:爬楼梯 = 斐波那契的初值变体()。手算:递推填表。
排除法:B(8)是 ;C(21)是 ;D(5)是 。
关联 · 爬楼梯问题(C6):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 long long s = 1; 05 for (int i = 1; i <= 6; i++) s *= i; // 循环版阶乘 06 cout << s; 07 return 0; 08}
单选题:程序输出是?
考点:循环求阶乘(K3)。
解析:。正确答案 A。
实现要点:循环版阶乘 = 累乘器 s *= i。手算:从 1 乘到 6。
排除法:B(120)是 ;C(5040)是 ;D(6)没乘。
关联 · 递归与循环的转换(A4):阶乘的循环写法。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {3, 1, 4, 1, 5}; 05 int s[6] = {0}; 06 for (int i = 1; i <= 5; i++) 07 s[i] = s[i - 1] + a[i - 1]; // 前缀和递推 08 for (int i = 1; i <= 5; i++) cout << s[i] << " "; 09 return 0; 10}
单选题:程序输出是?
考点:递推前缀和(K4)。
解析:s[i] = s[i-1] + a[i-1]:3, 4, 8, 9, 14。正确答案 A。
实现要点:前缀和框架 = s[i] = s[i-1] + a[i-1](1 下标)。手算:逐项累加。
排除法:B 是原数组;C 是后缀和;D 是 的误解。
关联 · 递推的定义(C1):前缀和是最常用的递推。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int c[6][6] = {0}; 05 for (int i = 0; i <= 5; i++) { 06 c[i][0] = c[i][i] = 1; // 两边都是 1 07 for (int j = 1; j < i; j++) 08 c[i][j] = c[i - 1][j - 1] + c[i - 1][j]; // 递推公式 09 } 10 for (int j = 0; j <= 5; j++) cout << c[5][j] << " "; 11 return 0; 12}
单选题:程序输出是?
考点:杨辉三角的递推(K5)。
解析:,第 5 行 = 1 5 10 10 5 1。正确答案 A。
实现要点:杨辉三角 = 边界两边 1 + 上方两数相加。手算:逐行填表,第 行有 个数。
排除法:B 是第 4 行;C 漏一个 10;D 漏两边的 1。
关联 · 递推的三要素(C3):二维递推的代表。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 const int MOD = 1000000007; 05 long long a = 1, b = 1; // f(1), f(2) 06 for (int i = 3; i <= 8; i++) { 07 long long c = (a + b) % MOD; // 边算边取模 08 a = b; b = c; // 滚动更新 09 } 10 cout << b; 11 return 0; 12}
单选题:程序输出是?
考点:递推取模(K6)。
解析:滚动变量求 ,每步 % MOD(结果未超模,值不变)。正确答案 A。
实现要点:滚动 + 取模 = c = (a + b) % MOD; a = b; b = c;—— 时间 空间。手算:只跟两个变量走。
排除法:B(13)是 ;C(34)是 ;D(55)是 。
关联 · 递推中的取模(G3):防溢出的标准操作。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 5, d[6] = {0}; // 1 下标差分数组(原数组全 0) 05 int l = 1, r = 3, x = 2; 06 d[l] += x; // 区间 [1,3] 加 2 07 d[r + 1] -= x; 08 for (int i = 1; i <= n; i++) { // 前缀和还原 09 d[i] += d[i - 1]; 10 cout << d[i] << " "; 11 } 12 return 0; 13}
单选题:程序输出是?
考点:差分区间加输出(L1)。
解析:d[1] += 2、d[4] -= 2,前缀和还原 → 2 2 2 0 0。正确答案 A。
实现要点:差分三步 = 头标记 + 尾标记 + 前缀和还原。手算:逐位累加 的前缀和。
排除法:B 区间位置错;C 缺尾标记;D 方向反。
关联 · 区间加的差分标记(F2):概念题的代码版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 5, d[6] = {0}; 05 d[1] = 1; d[3] = -1; // 相当于区间 [1,2] 加 1 的标记 06 for (int i = 1; i <= n; i++) { 07 d[i] += d[i - 1]; 08 cout << d[i] << " "; 09 } 10 return 0; 11}
单选题:程序输出是?
考点:差分还原输出(L2)。
解析:d[1] = 1、d[3] = -1 = 区间 加 1,还原 → 1 1 0 0 0。正确答案 A。
实现要点:还原 = 边累加边输出。手算:。
排除法:B 是没还原的差分数组;C 缺尾标记;D 无依据。
关联 · 差分还原成原数组(F3):概念题的代码版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int x = 1, cnt = 0; 05 while (x < 1000) { // 每次翻倍 06 x *= 2; 07 cnt++; 08 } 09 cout << cnt; 10 return 0; 11}
单选题:程序输出是?
考点:翻倍需要的次数(L3)。
解析:,翻倍 次达到 。正确答案 A。
实现要点:倍增计数 = x *= 2 + 计数循环。手算:。
排除法:B(9)是 (未到);C 是阈值;D 多一次。
关联 · 倍增的思想(E4):对数级的直观验证。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 13, p = 1; 05 while (n) { 06 if (n & 1) cout << p << " "; // 该位为 1 对应的 2 的幂 07 n >>= 1; 08 p <<= 1; 09 } 10 return 0; 11}
单选题:程序输出是?
考点:二进制拆分输出(L4)。
解析: → 1 4 8。正确答案 A。
实现要点:拆分 = n & 1 判断该位 + n >>= 1 移位 + p <<= 1 位权翻倍。手算:逐位看二进制。
排除法:B 是逆序;C 多拆了 2;D 是原数。
关联 · 快速幂与倍增(E5):拆分是快速幂的底层。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 5, d[6] = {0}; 05 d[2] += 3; d[5] -= 3; // 区间 [2,4] 加 3 06 d[1] += 1; d[3] -= 1; // 区间 [1,2] 加 1 07 for (int i = 1; i <= n; i++) { 08 d[i] += d[i - 1]; 09 cout << d[i] << " "; 10 } 11 return 0; 12}
单选题:程序输出是?
考点:差分与前缀和综合输出(L5)。
解析:两次区间加叠加后还原: → 1 4 3 3 0。正确答案 A。
实现要点:多次标记全部累加后再统一还原——先改后查。手算:,前缀和 。
排除法:B 漏了第二个区间的首标记;C 起点错;D 尾标记错。
关联 · 差分与前缀和综合(F7):综合套路的代码版。
01#include <bits/stdc++.h> 02using namespace std; 03int n = 3, a[5], used[5] = {0}, cnt = 0; 04void dfs(int k) { // 正在放第 k 个位置(0 开始) 05 if (k == n) { cnt++; return; } // 排满一种 06 for (int i = 1; i <= n; i++) 07 if (!used[i]) { 08 used[i] = 1; // 选择 09 a[k] = i; 10 dfs(k + 1); // 递归 11 used[i] = 0; // 撤销 12 } 13} 14int main() { dfs(0); cout << cnt; return 0; }
单选题:程序输出是?
考点:全排列回溯计数(M1)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:3 个元素的排列数 ,回溯穷举所有排列后 cnt = 6。正确答案 A。
实现要点:全排列框架 = used[] 标记 + 选择(used[i]=1, a[k]=i)+ 递归 dfs(k+1) + 撤销(used[i]=0)。手算:第一层 3 种、第二层 2 种、第三层 1 种 → 。
排除法:B(3)只数了第一层;C(9)是 ;D(12)无依据。
关联 · 回溯三部曲(D2):选择-递归-撤销的完整示范。
单选题: 个不同元素的全排列共有多少个?
考点:全排列的个数(M2)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:。正确答案 A。
排除法:B(12)是 ;C(8)是 ;D(16)是 。
关联 · 全排列的数量(D4): 的规律。
01#include <bits/stdc++.h> 02using namespace std; 03int n = 3, cnt = 0; 04void dfs(int k) { // 对第 k 个元素做选择 05 if (k > n) { cnt++; return; } // 每个元素都决定完 = 一个子集 06 dfs(k + 1); // 不选 k 07 dfs(k + 1); // 选 k 08} 09int main() { dfs(1); cout << cnt; return 0; }
单选题:程序输出是?
考点:子集回溯计数(M3)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:每个元素两个分支(选/不选),叶子数 。正确答案 A。
实现要点:子集框架 = dfs(k+1) 两次(选/不选),出口 k > n 计数。手算:画二叉树,深度 3、叶子 8。
排除法:B(6)是排列数;C(3)是元素数;D 无依据。
关联 · 子集的数量(D5): 的规律。
01#include <bits/stdc++.h> 02using namespace std; 03int n = 5, k = 3, cnt = 0, a[10]; 04void dfs(int pos, int st) { // 已选 pos 个,从 st 开始选下一个 05 if (pos == k) { cnt++; return; } 06 for (int i = st; i <= n; i++) { 07 a[pos] = i; 08 dfs(pos + 1, i + 1); // 递增选数,避免重复组合 09 } 10} 11int main() { dfs(0, 1); cout << cnt; return 0; }
单选题:程序输出是?
考点:组合回溯计数(M4)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:。正确答案 A。
实现要点:组合框架 = 递增选数 dfs(pos+1, i+1)(只向后选,避免重复组合)。手算:枚举 (1,2,3)...(3,4,5) 共 10 组。
排除法:B(6)是 ;C(5)是 ;D(20)是 的误解。
关联 · 回溯三部曲(D2):组合与排列的区别在"起点递增"。
01#include <bits/stdc++.h> 02using namespace std; 03int a[5] = {2, 3, 5, 6, 8}; 04int n = 5, target = 8, cnt = 0; 05void dfs(int i, int s) { // 考虑 a[i],当前和为 s 06 if (s == target) { cnt++; return; } 07 if (i == n || s > target) return; // 提前返回:越界或和已超 08 dfs(i + 1, s + a[i]); // 选 a[i] 09 dfs(i + 1, s); // 不选 a[i] 10} 11int main() { dfs(0, 0); cout << cnt; return 0; }
单选题:程序输出是?
考点:回溯凑数和(M5)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:和为 8 的子集:{8}、{2,6}、{3,5} 共 3 种。正确答案 A。
实现要点:凑数框架 = 选/不选 + 提前返回(s > target 立即返回、i == n 越界返回)。手算:按 DFS 顺序列出子集,和为 target 的计数。
排除法:B(2)漏了 {8};C(4)多数;D 无依据。
关联 · 回溯与枚举的关系(D6):凑数 = 子集枚举的变体。
01#include <bits/stdc++.h> 02using namespace std; 03int n = 4, cnt = 0, col[5] = {0}; 04bool ok(int k, int i) { // 第 k 行的皇后放第 i 列是否合法 05 for (int j = 1; j < k; j++) 06 if (col[j] == i || abs(col[j] - i) == k - j) return false; // 同列或同斜线 07 return true; 08} 09void dfs(int k) { // 正在放第 k 行的皇后 10 if (k == n + 1) { cnt++; return; } 11 for (int i = 1; i <= n; i++) 12 if (ok(k, i)) { col[k] = i; dfs(k + 1); } 13} 14int main() { dfs(1); cout << cnt; return 0; }
单选题:程序输出是?
考点:四皇后计数(M6)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:4 皇后共有 2 种合法摆法(对称的两种)。正确答案 A。
实现要点:N 皇后框架 = 逐行放 + ok(k, i) 检查同列(col[j] == i)与同斜线(|col[j]-i| == k-j)+ 递归。手算:第 1 行逐个试列,不合法即跳过。
排除法:B(4)是行数;C(8)是 8 皇后的部分解误解;D(92)是 8 皇后的解数。
关联 · 回溯与枚举的关系(D6):皇后问题 = 候选分支的枚举。
判断题:回溯在递归返回后必须撤销本次选择(如 used[i] = 0、弹出已选元素),否则后续分支会误以为该元素仍被占用,导致漏解。
考点:回溯撤销现场(M7)。
大纲注:回溯在 NOI 2025 大纲中未单列条目,属 DFS 的枚举应用、初赛完善程序常考。
解析:不撤销 → used 一直占用 → 后续分支误以为元素不可用 → 大量漏解。✅ 正确
排除法:无(判断题)。混淆点:撤销必须与选择严格配对(选了什么就撤什么)。
关联 · 忘记撤销的回溯(P3):3 个元素只剩 1 种排列的实证。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[6] = {0, 2, 5, 1, 4, 3}; // 1 下标原数组 05 int d[6] = {0}; 06 d[1] = a[1]; 07 for (int i = 2; i <= 5; i++) d[i] = a[i] - a[i - 1]; 08 for (int i = 1; i <= 5; i++) cout << d[i] << " "; 09 return 0; 10}
单选题:程序输出是?
考点:差分数组构造输出(N1)。
解析:()。正确答案 A。
实现要点:构造 = d[1] = a[1] + 循环做差。手算:逐位相减。
排除法:B 是原数组;C 是逆序做差;D 符号错。
关联 · 差分数组的构造(F1):概念题的代码版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 6, d[7] = {0}; 05 d[2] += 3; d[6] -= 3; // 区间 [2,5] 加 3 06 for (int i = 1; i <= n; i++) { 07 d[i] += d[i - 1]; 08 cout << d[i] << " "; 09 } 10 return 0; 11}
单选题:程序输出是?
考点:区间加还原输出(N2)。
解析:区间 加 3 → 0 3 3 3 3 0。正确答案 A。
实现要点:d[2] += 3、d[6] -= 3 + 前缀和还原。手算:逐位累加。
排除法:B 首元素错;C 尾标记漏(区间拖到结尾);D 区间位置错。
关联 · 差分区间加输出(L1):同框架不同数据。
01#include <bits/stdc++.h> 02using namespace std; 03long long pw(long long a, long long b) { 04 long long r = 1; 05 while (b) { 06 if (b & 1) r = r * a; // b 的二进制当前位是 1 07 a = a * a; // a 翻倍:a, a^2, a^4, ... 08 b >>= 1; 09 } 10 return r; 11} 12int main() { cout << pw(2, 10); return 0; }
单选题:程序输出是?
考点:快速幂(N3)。
解析:(二进制 1010:乘 )。正确答案 A。
实现要点:快速幂 = b & 1 时 r *= a、a *= a(平方翻倍)、b >>= 1。手算:把指数写成二进制,逐位决定乘不乘。
排除法:B(512)是 ;C(20)是 ;D(100)是 。
关联 · 快速幂与倍增(E5):指数每步减半。
01#include <bits/stdc++.h> 02using namespace std; 03const long long MOD = 1000000007; 04long long pw(long long a, long long b) { 05 long long r = 1; 06 while (b) { 07 if (b & 1) r = r * a % MOD; 08 a = a * a % MOD; 09 b >>= 1; 10 } 11 return r; 12} 13int main() { 14 cout << pw(3, 5) << " " << pw(2, 10); 15 return 0; 16}
单选题:程序输出是?
考点:快速幂取模(N4)。
解析:、(均小于模,直接输出原值)→ 243 1024。正确答案 A。
实现要点:快速幂取模 = 每次乘法后 % MOD。手算:结果未超模时与普通快速幂一致。
排除法:B(1023)是 ;C(15 20)是 与 的误解;D 第二个错了。
关联 · 递推中的取模(G3):同款"边算边模"。
01#include <bits/stdc++.h> 02using namespace std; 03int a[7] = {1, 3, 5, 7, 9, 11, 13}; // 升序数组 04int f(int l, int r, int x) { // 在 [l, r] 中找 x 05 if (l > r) return -1; 06 int m = (l + r) / 2; 07 if (a[m] == x) return m; 08 if (a[m] < x) return f(m + 1, r, x); 09 return f(l, m - 1, x); 10} 11int main() { cout << f(0, 6, 9); return 0; }
单选题:程序输出是?
考点:递归二分查找(N5)。
解析:f(0,6,9):m=3 得 7 < 9 → f(4,6);m=5 得 11 > 9 → f(4,4);m=4 命中 → 返回 4。正确答案 A。
实现要点:递归二分 = 出口 l > r 返回 -1 + 三分支(命中/去右半/去左半)。手算:每层写 l, m, r 三值。
排除法:B(9)是值不是下标;C(-1)是找不到的结果;D(5)是 11 的下标。
关联 · 二分查找是减治(F5):每层只留一半。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int h[10]; 05 h[1] = 1; // 1 个盘只需 1 步 06 for (int i = 2; i <= 5; i++) 07 h[i] = 2 * h[i - 1] + 1; // 递推公式 08 cout << h[5]; 09 return 0; 10}
单选题:程序输出是?
考点:汉诺塔次数递推(N6)。
解析:,。正确答案 A。
实现要点:递推填表 h[i] = 2*h[i-1] + 1。手算:逐项翻倍加一。
排除法:B(15)是 ;C(63)是 ;D(16)是 。
关联 · 汉诺塔的递推式(B5):公式的填表实现。
01#include <bits/stdc++.h> 02using namespace std; 03void h(int n, char a, char b, char c) { // n 个盘从 a 柱移到 c 柱,b 辅助 04 if (n == 1) { cout << a << "->" << c << " "; return; } 05 h(n - 1, a, c, b); // 上面 n-1 个盘先移到 b 06 cout << a << "->" << c << " "; // 最大的盘移到 c 07 h(n - 1, b, a, c); // n-1 个盘从 b 移到 c 08} 09int main() { h(3, 'A', 'B', 'C'); return 0; }
单选题:程序输出是?
考点:汉诺塔移动步骤(N7)。
解析:3 盘 7 步:A->C A->B C->B A->C B->A B->C A->C。正确答案 A。
实现要点:汉诺塔框架 = 出口单盘直移 + 三步:上 n-1 盘 A→B(借 C)→ 最大盘 A→C → n-1 盘 B→C(借 A)。手算:把"移 n-1 盘"当成一步展开。
排除法:B 首步 A->B 错误(单盘应直接 A->C 时第一步如此,但 3 盘第一步是把小盘移到 C);C 只有 3 步;D 次序错。
关联 · 汉诺塔次数递推(N6):步骤数 = 递推式。
01#include <bits/stdc++.h> 02using namespace std; 03int f(int n) { 04 if (______) return 1; // 边界:0! = 1 05 return n * f(n - 1); 06} 07int main() { cout << f(5); return 0; }
单选题:横线处应填入?
考点:补全阶乘递归(O1)。
解析: 是标准出口,填 n == 0。运行:。正确答案 A。
实现要点:阶乘出口写 (覆盖 );写 n == 1 在 时会死递归。
排除法:B(n == 1)遇 无限递归;C/D 条件与递归无关。
关联 · 递归出口写在前面(G1):出口必须覆盖最小情形。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 long long f[40]; 05 f[1] = f[2] = 1; 06 for (int i = 3; i <= 20; i++) 07 f[i] = ______; // 递推公式 08 cout << f[20]; 09 return 0; 10}
单选题:横线处应填入?
考点:补全斐波那契递推(O2)。
解析:递推公式 f[i] = f[i-1] + f[i-2];运行 。正确答案 A。
实现要点:递推填表 = 初始值两行 + 循环递推式。手算核对:。
排除法:B 是乘法(无依据);C 加常数 i;D 是等比 的误解。
关联 · 递推的三要素(C3):递推公式是核心要素。
01#include <bits/stdc++.h> 02using namespace std; 03int n = 3, a[5], used[5] = {0}; 04void dfs(int k) { 05 if (k == n) { 06 for (int i = 0; i < n; i++) cout << a[i] << " "; 07 cout << endl; 08 return; 09 } 10 for (int i = 1; i <= n; i++) 11 if (!used[i]) { 12 used[i] = 1; 13 a[k] = i; 14 dfs(k + 1); 15 ______; // 撤销,恢复现场 16 } 17} 18int main() { dfs(0); return 0; }
单选题:横线处应填入?
考点:补全回溯撤销(O3)。
解析:递归返回后恢复现场,填 used[i] = 0。正确答案 A。
实现要点:撤销与选择配对:选了 used[i] = 1,回来就 used[i] = 0——回溯三部曲的第三步。
排除法:B 又置 1(等于没撤);C 清的是 a[k] 不是标记;D 提前返回会漏掉后续循环。
关联 · 回溯撤销现场(M7):撤销的必要性。
01#include <bits/stdc++.h> 02using namespace std; 03long long pw(long long a, long long b) { 04 long long r = 1; 05 while (b) { 06 if (______) r = r * a; // b 的二进制当前位为 1 才乘 07 a = a * a; 08 b >>= 1; 09 } 10 return r; 11} 12int main() { cout << pw(2, 10); return 0; }
单选题:横线处应填入?
考点:补全快速幂(O4)。
解析:指数二进制当前位为 1 才乘,填 b & 1。运行 。正确答案 A。
实现要点:b & 1 取最低位;b >>= 1 右移;a *= a 同步平方。手算:,第 2、4 位为 1 → 乘 与 。
排除法:B(b & 2)只在位 2 为 1 时乘(漏乘);C/D 无依据。
关联 · 快速幂(N3):填空版同款题。
01#include <bits/stdc++.h> 02using namespace std; 03int s(int n) { // 求 1 + 2 + ... + n 04 if (______) return 0; 05 return n + s(n - 1); 06} 07int main() { cout << s(100); return 0; }
单选题:横线处应填入?
考点:补全递归边界(O5)。
解析: 是求和出口,填 n == 0。运行 。正确答案 A。
实现要点:求和出口 n == 0 返回 0(比 n == 1 返回 1 更通用)。手算核对 。
排除法:B(n == 100)只对 f(100) 生效一次;C(n > 0)与递归条件冲突;D 无依据。
关联 · 递归求 1 到 n 的和(I3):出口写法的对比。
01#include <bits/stdc++.h> 02using namespace std; 03int f(int n) { 04 // 缺少边界条件 05 return n + f(n - 1); 06} 07int main() { f(5); return 0; }
单选题:程序会发生什么?
考点:缺边界的递归(P1)。
解析:f(n) 永远调 f(n-1),n 减到负无穷也不停 → 栈溢出。正确答案 A。
实现要点:递归正确性的第一检查点 = "出口是否先于递归调用、且条件能被触及"。补上 if (n == 0) return 0; 即恢复正常。
排除法:B(15)是正常求和 的结果;C 无依据;D——缺边界能编译,运行时才崩溃。
关联 · 缺少边界条件(H1):概念题的代码实证。
01#include <bits/stdc++.h> 02using namespace std; 03int f(int n) { 04 if (n == 1) return 1; 05 f(n - 1) * n; // 错误:计算结果没有 return 06} 07int main() { cout << f(5); return 0; }
单选题:程序会发生什么?
考点:丢失 return 的递归(P2)。
解析:非 void 函数走到末尾没有 return → 返回值未定义(常见环境返回寄存器垃圾值)。正确答案 A。
实现要点:递归函数每个分支都要有返回值:出口分支 return、递归分支 return f(...)。写完自查一句"每条路径都有 return 吗"。
排除法:B(120)是正确写法;C(1)是出口值;D——C++ 允许编译(行为未定义)。
关联 · return 的丢失(H3):递归结果靠 return 层层上传。
01#include <bits/stdc++.h> 02using namespace std; 03int n = 3, used[4] = {0}, cnt = 0, a[4]; 04void dfs(int k) { 05 if (k == n) { cnt++; return; } 06 for (int i = 1; i <= n; i++) 07 if (!used[i]) { 08 used[i] = 1; 09 a[k] = i; 10 dfs(k + 1); 11 // 错误:缺少 used[i] = 0 12 } 13} 14int main() { dfs(0); cout << cnt; return 0; }
单选题:程序输出是?(正确结果应为 6)
考点:忘记撤销的回溯(P3)。
解析:used 永不复位:第一条路径 1→2→3 排完后,所有元素都被标记占用,再无其他排列 → cnt = 1(正确是 6)。正确答案 A。
实现要点:回溯的"撤销"要与"选择"严格配对——循环体内 used[i] = 1; dfs(k+1); used[i] = 0; 三行必须同处一个分支里,缺第三行就是本题。
排除法:B(6)是正确写法的结果;C/D 无依据。
关联 · 回溯撤销现场(M7):撤销是回溯正确性的保证。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int f[10]; 05 f[1] = 1; f[2] = 2; // 爬楼梯初始值 06 for (int i = 2; i <= 4; i++) // 错误:循环应从 3 开始 07 f[i] = f[i - 1] + f[i - 2]; // f[2] 被覆盖成 1(f[0] 未初始化) 08 cout << f[4]; 09 return 0; 10}
单选题:程序输出是?(正确结果应为 5)
考点:递推初值被覆盖(P4)。
解析:循环从 i = 2 开始,把 覆盖成 (f[0] 未初始化按 0 算)→ 后续全错,。正确答案 A。
实现要点:填表起点必须在"已有初始值的下一项"(此处应为 i = 3)。手算:先写出被覆盖的初值,再沿错链推算。
排除法:B(5)是正确结果;C/D 是错误链上的中间值。
关联 · 递推初值写错(H4):初值是链条的第一环。
01#include <bits/stdc++.h> 02using namespace std; 03int cnt = 0; 04int fib(int n) { 05 cnt++; // 每次进入计数 06 if (n == 1 || n == 2) return 1; 07 return fib(n - 1) + fib(n - 2); 08} 09int main() { fib(6); cout << cnt; return 0; }
单选题:程序输出是?
考点:递归重复计算的次数(P5)。
解析:不缓存结果的朴素递归 的总调用次数 = 15()。正确答案 A。
实现要点:调用次数递推 ,。手算:逐项列出 。
排除法:B(6)是参数;C(8)是 的值;D(21)是 的值。
关联 · 斐波那契递归的重复计算(B3):指数爆炸的量化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int f[5]; // 下标范围 0 ~ 4 05 f[1] = f[2] = 1; 06 for (int i = 3; i <= 5; i++) // 错误:f[5] 越界 07 f[i] = f[i - 1] + f[i - 2]; 08 cout << f[5]; 09 return 0; 10}
单选题:程序会发生什么?
考点:递推数组越界(P6)。
解析:f[5] 只有下标 ,循环 i <= 5 写 f[5] → 越界(行为未定义)。正确答案 A。
实现要点:递推数组大小 = 目标项下标 + 1;循环上界与数组声明必须一致——写代码时先确认"最大下标是多少"。
排除法:B(5)是正确下标范围内的结果;C 同理;D——越界是运行时行为,编译不报错。
关联 · 递推的循环实现(C7):数组开多大 = 目标项下标 + 1。