CSP-J 第一轮(初赛)通关集训 · 第二天
Day 2 上午:C++ 语言核心基础、类型转换溢出与控制结构(3小时)
第一部分:核心知识精讲与考点速记
1. C++ 程序基本结构与标识符规范
- 基础模板与头文件:
cpp #include <iostream> // 输入输出流标准头文件 #include <cmath> // 常用数学函数库(sqrt, pow, abs, ceil, floor) #include <algorithm> // 算法库(min, max, swap, sort) using namespace std; // 使用标准命名空间 int main() { // 程序入口,返回 0 表示正常退出 return 0; } - 标识符命名规则(初赛常考语法选择题):
- 只能由英文字母(区分大小写)、数字和下划线(
_)组成。 - 第一个字符必须是字母或下划线,绝对不能以数字开头(如
2a,3_sum非法)。 - 不能使用 C++ 关键字(如
int,struct,for,class,const等)。
- 只能由英文字母(区分大小写)、数字和下划线(
- 常量定义方式:
const int MAXN = 1000;(具备类型检查,推荐)。#define MAXN 1000(预编译宏替换,无类型检查)。
2. 基本数据类型与存储范围(初赛必背)
- 数据类型大小与范围全景表(64位系统):
| 数据类型 | 关键字 | 字节数 (Byte) | 取值范围 | 初赛典型用途 |
|---|---|---|---|---|
| 布尔型 | bool |
1 | true (1), false (0) |
逻辑判断与状态标记 |
| 字符型 | char |
1 | $-128 \sim +127$ (ASCII: $0 \sim 127$) | 单个字符存储 |
| 标准整型 | int |
4 | $-2^{31} \sim 2^{31}-1 \approx \pm 2.14 \times 10^9$ | 绝大多数循环与计数 |
| 无符号整型 | unsigned int |
4 | $0 \sim 2^{32}-1 \approx 4.29 \times 10^9$ | 正数大范围计数 |
| 长整型 | long long |
8 | $-2^{63} \sim 2^{63}-1 \approx \pm 9.22 \times 10^{18}$ | 累加求和、防乘法溢出 |
| 单精度浮点 | float |
4 | 约 6~7 位有效数字 | 占用空间小的实数 |
| 双精度浮点 | double |
8 | 约 15~16 位有效数字 | 高精度科学与几何计算 |
- 初赛高频陷阱:
struct(结构体)、class(类)、union(联合体)属于用户自定义复合类型,不是基本数据类型。- 当计算可能超过 $2 \times 10^9$ 时(如累乘、组合数相乘、前缀和累加),必须使用
long long,否则会发生整数上溢(Overflow)导致负数错误。
3. 类型转换机制与运算符陷阱(阅读程序大题重灾区)
- 整数除法的“截断”陷阱:
- 两个整型相除,结果依然是整型,小数部分直接舍弃(向零截断):
1 / 2结果为0;7 / 4结果为1;-7 / 4结果为-1。- 若要保留小数,参与运算的数中必须至少有一个为浮点型:
1.0 / 2 = 0.5,(double)1 / 2 = 0.5。
- 两个整型相除,结果依然是整型,小数部分直接舍弃(向零截断):
- 强制类型转换与四舍五入公式:
- 浮点转整型
(int)3.8直接截断小数得3(不会自动四舍五入)。 - 四舍五入保留两位小数经典模板(必背): $$\text{保留两位四舍五入} \implies \text{x = (int)(x * 100 + 0.5) / 100.0}$$
- 浮点转整型
- 自增与自减运算符细节:
++i(前置自增):先将 $i$ 加 1,再作为整个表达式的值返回(“先加后用”)。i++(后置自增):先取出 $i$ 的原值参与表达式计算,计算完毕后 $i$ 再加 1(“先用后加”)。
- 字符与数值的偏移计算:
'a' + 13表示字符'a'的 ASCII 码向后偏移 13 位,得到英文字母表第 14 个字母'n'。
4. 流程控制结构与分支循环手推规则
- 分支结构与
else悬空配对原则:- 在没有花括号
{}显式限定时,C++ 规定else永远与前面最近的未配对的if结合。
- 在没有花括号
switch-case的“穿透特性(Fall Through)”:switch(x)会跳转到匹配的case入口执行。如果该分支末尾没有break;,程序会无视后续case标签,一直顺序向下执行所有后续分支代码,直到遇到break或switch结束。
- 循环语句对比与执行次数手算:
for(初始化; 条件判断; 步进):先判断后执行。while(条件):当型循环,先判断后执行。do { 循环体; } while(条件);:直到型循环,无论条件是否满足,循环体至少无条件执行 1 次。
breakvscontinue:break:立刻彻底终止并跳出当前所在的最内层循环。continue:立刻跳过本次循环体中剩余的代码,直接进入下一次循环的条件判断/步进。
第二部分:上午精选真题实战(1~20题)
-
在 32 位编译环境下,C++ 中标准
int类型变量的数值存储范围是( )。 A. $-2147483647 \sim +2147483647$ B. $-2147483647 \sim +2147483648$ C. $-2147483648 \sim +2147483647$ D. $-2147483648 \sim +2147483648$ -
一个 32 位无符号整数(
unsigned int)所能表示的最大正整数最接近于( )。 A. $4 \times 10^9$ B. $3 \times 10^{10}$ C. $2 \times 10^9$ D. $2 \times 10^{10}$ -
以下各项中,不属于 C++ 基本数据类型的是( )。 A.
intB.floatC.structD.char -
在 C++ 语言中,用于声明常量的关键字是( )。 A.
unsignedB.constC.staticD.mutable -
某程序试图计算 $s = 1 + \frac{1}{2} + \frac{1}{3} + \dots + \frac{1}{10}$,下列代码中存在严重逻辑错误的一行是( )。
cpp // 行号与代码如下: double s = 1.0; // 行 A for (int n = 10; n > 1; n--) // 行 B s = s + 1 / n; // 行 C cout << s << endl; // 行 DA. 行 A B. 行 B C. 行 C D. 行 D -
下列表达式中,能够正确实现将浮点数 $x$ 四舍五入保留两位小数的是( )。 A.
x = (x * 100) + 0.5 / 100.0B.x = (x * 100 + 0.5) / 100.0C.x = (int)(x * 100 + 0.5) / 100.0D.x = (x / 100 + 0.5) * 100.0 -
阅读下列程序段,当输入参数 $n = -3$ 时,变量 $s$ 的最终输出结果是( )。
cpp int a = 1, s = 0, n; cin >> n; while (a != n) { a -= 2; s++; } cout << s << endl;A. 1 B. 2 C. 3 D. 4 -
阅读下列代码段,若 $a$ 和 $c$ 均为正整数,则输出的 $s$ 值等价于( )。
cpp int s = a; for (int i = 0; i < c; i++) { s++; } cout << s << endl;A. $a \times c$ B. $a + c$ C. $a^c$ D. $a - c$ -
阅读下列代码段,执行完毕后变量 $n$ 和 $k$ 的最终值分别为( )。
cpp int n = 0, k = 5; while (k > 0) { n++; if (n == 1 || n == 2) continue; k--; if (n == 3) break; }A. $n=3, k=4$ B. $n=3, k=3$ C. $n=4, k=4$ D. $n=3, k=5$ -
阅读下列程序段,执行完毕后变量 $s$ 的值等价于( )。
cpp int s = a; for (int i = 0; i < c; i++) { s--; }A. $a + c$ B. $a - c$ C. $c - a$ D. $a \times c$ -
在 C++ 中对整型变量 $a = -5$ 执行
(double)a强制类型转换后,下列说法正确的是( )。 A. 仅改变数据精度,符号和数值大小保持不变 B. 变为正数 5.0 C. 变为无符号大整数 D. 引发编译错误 -
下列代码段执行完毕后,变量 $sum$ 的最终输出值是( )。
cpp int i = 1, sum = 0; do { sum += i; i++; } while (i <= 100); cout << sum << endl;A. 5050 B. 5000 C. 5151 D. 4950 -
下列语句中,不属于 C++ 语言合法循环控制语句关键字的是( )。 A.
forB.whileC.do-whileD.repeat-until -
在 C++ 中执行表达式
'a' + 13,其运算结果所对应的字符是( )。 A.'m'B.'n'C.'o'D.'l' -
下列有关 C++ 标识符的命名中,合法的是( )。 A.
2_sumB._totalCountC.intD.my-name -
阅读下列程序段,输出结果是( )。
cpp int x = 2; switch (x) { case 1: cout << "A"; case 2: cout << "B"; case 3: cout << "C"; break; default: cout << "D"; }A. B B. BC C. BCD D. ABC -
执行语句
int a = 5, b = 2; double c = a / b;后,变量c的值是( )。 A. 2.5 B. 2.0 C. 2 D. 3.0 -
阅读下列嵌套循环代码,内层语句
cnt++总共被执行的次数是( )。cpp int cnt = 0; for (int i = 1; i <= 4; i++) { for (int j = 1; j <= i; j++) { cnt++; } }A. 16 B. 10 C. 12 D. 8 -
执行下列代码段后,输出的 $x$ 和 $y$ 的值分别为( )。
cpp int a = 5; int x = ++a; int y = a++; cout << x << " " << y << endl;A. 6 6 B. 6 7 C. 5 6 D. 6 5 -
设整型变量 $x=1, y=2, z=3$,执行下列分支语句后 $x$ 的值是( )。
cpp if (x > y) if (y > z) x = z; else x = y; else x = 0;A. 3 B. 2 C. 0 D. 1
第三部分:上午真题解析与答案速查
- 【答案】C
【解析】 在标准 32 位补码体系下,int占 4 字节(32 位),最高位为符号位。其取值范围是 $-2^{31} \sim 2^{31}-1$,即 $-2147483648 \sim +2147483647$。 - 【答案】A
【解析】 32 位无符号整型的最大值为 $2^{32}-1 = 4294967295 \approx 4.29 \times 10^9$,最接近 $4 \times 10^9$。 - 【答案】C
【解析】struct属于用户自定义复合数据类型;int,float,char,double,bool均为 C++ 语言内置的基本数据类型。 - 【答案】B
【解析】const用于声明具有常量性质的变量(只读);unsigned声明无符号数;static声明静态变量;mutable用于结构体/类中可变成员。 - 【答案】C
【解析】 行 C 中1 / n的操作数1和n都是整型,发生整型除法向零截断,当 $n \ge 2$ 时1 / n恒等于0,无法实现累加分数,必须改为1.0 / n。 - 【答案】C
【解析】 A、B 选项中未将中间结果转为整型截断;D 选项缩放反了;C 选项先乘以 100 加上 0.5 强转为int截断多余小数,再除以 100.0 恢复浮点数,是标准的四舍五入保留两位小数写法。 - 【答案】B
【解析】 手动模拟变量跟踪:初始 $a=1, s=0$。第 1 轮循环:$a = 1 - 2 = -1, s = 1$;第 2 轮循环:$a = -1 - 2 = -3, s = 2$。此时 $a == n (-3)$,退出while循环,输出 $s = 2$。 - 【答案】B
【解析】 变量 $s$ 初始值为 $a$,for循环从 $i=0$ 到 $c-1$ 共循环执行了 $c$ 次s++操作,最终 $s = a + c$。 - 【答案】A
【解析】 逐轮追踪: - 第 1 轮:$n=1$,满足
n==1执行continue; - 第 2 轮:$n=2$,满足
n==2执行continue; - 第 3 轮:$n=3$,不满足
continue,执行k--变为 $4$;随后满足n==3执行break彻底跳出循环。最终 $n=3, k=4$。 - 【答案】B
【解析】 循环体执行 $c$ 次每次自减 1,等价于 $s = a - c$。 - 【答案】A
【解析】 强制类型转换只改变数据的内部存储形式与表示精度,不改变数值正负及大小本身,转换后结果为-5.0。 - 【答案】A
【解析】do-while循环完成了等差数列 $1 + 2 + 3 + \dots + 100$ 的求和,由高斯求和公式 $\frac{100 \times 101}{2} = 5050$。 - 【答案】D
【解析】repeat-until是 Pascal 语言的循环关键字,C++ 中的循环关键字只有for,while,do-while。 - 【答案】B
【解析】 字符'a'加上 13 对应字母表中向后数第 13 个字符,即第 14 个英文字母'n'。 - 【答案】B
【解析】 A 选项数字开头非法;C 选项int为关键字非法;D 选项包含了减号-(非下划线)非法;B 选项以下划线开头完全合法。 - 【答案】B
【解析】 $x=2$ 匹配到case 2:输出"B";由于该行末尾没有break;,程序发生“穿透”,继续向下执行case 3:输出"C",遇到break;退出。综合输出"BC"。 - 【答案】B
【解析】 赋值运算符右侧a / b为整型除法 $5 / 2 = 2$;随后隐式类型转换为浮点数赋值给double c,故 $c = 2.0$。 - 【答案】B
【解析】 内层循环次数分别为 $i=1$ 时 1 次,$i=2$ 时 2 次,$i=3$ 时 3 次,$i=4$ 时 4 次。总次数为 $1 + 2 + 3 + 4 = 10$ 次。 - 【答案】A
【解析】 初始 $a=5$。执行int x = ++a;:$a$ 先加 1 变成 6,再赋值给 $x$,故 $x=6$;执行int y = a++;:先将 $a$ 的当前值 6 赋给 $y$(故 $y=6$),随后 $a$ 变为 7。输出6 6。 - 【答案】C
【解析】 $x=1, y=2$,外层if (x > y)条件为假,直接跳转执行最外层的else x = 0;,故 $x$ 最终为 0。
---
Day 2 下午:函数与参数传递、递归调用手推与复杂度分析(3小时)
第一部分:核心知识精讲与考点速记
1. 函数传参机制(值传递 vs 引用传递)
初赛阅读程序题中最容易扣分的细节是形参与实参的绑定关系:
* 值传递(Pass by Value):
* 定义格式:void solve(int a, int b)
* 原理:在函数调用时,系统会在栈区为形参分配新的内存空间,并将实参的值复制一份(副本)赋给形参。
* 结果:函数内部对形参的任何修改,绝对不会影响外部实参的原值。
* 引用传递(Pass by Reference):
* 定义格式:void solve(int &a, int b)
* 原理:形参带有取地址引用符号 &,此时形参成为了外部实参的别名(指向同一块内存地址)。
* 结果:函数内部对形参 a 的修改,会直接同步修改外部实参的值。
* 数组传参特性:
* 当数组作为函数参数时(如 void f(int a[])),传递的是数组首元素的内存地址(退化为指针),函数内修改数组元素会直接改变原数组。
2. 递归函数的设计原理与初赛人脑手推法
- 递归两大核心要素:
- 递归边界(Base Case):终止递归的条件,防止无限调用导致死循环或系统栈溢出(Stack Overflow)。
- 递推步(Recursive Step):将大问题拆解为形式相同但规模更小的子问题。
- 纸笔手推递归题的黄金法则——“画递归树与变量追踪表”:
- 分治型递归:自顶向下画出调用树分支,计算叶子节点的基准返回值,再自底向上汇总返回值。
- 例:$f(n) = f(n-1) + f(n-2)$,画出二叉树状调用关系。
3. 时间与空间复杂度分析全套方案
- 大 $O$ 渐进记号定义:
- 描述算法在输入规模 $n \to \infty$ 时的时间/空间增长趋势,忽略所有常数系数和低阶项。
- 常见时间复杂度大小排列(必须熟记): $$O(1) < O(\log n) < O(\sqrt{n}) < O(n) < O(n \log n) < O(n^2) < O(n^3) < O(2^n) < O(n!)$$
- 循环复杂度判定套路:
- 单层循环 $i$ 每次加 1:$O(n)$;
- 单层循环 $i$ 每次乘 2(
i *= 2):$O(\log n)$; - 双层嵌套独立循环:$O(n \times m)$ 或 $O(n^2)$;
- 外层 $i$ 从 1 到 $n$,内层 $j$ 从 1 到 $i$:$\sum_{i=1}^n i = \frac{n(n+1)}{2} = O(n^2)$。
- 空间复杂度计算规则:
- 算法运行过程中额外占用的内存空间(不含输入数据本身空间)。
- 递归调用的空间复杂度 = 递归树的最大深度 $\times$ 单层栈帧空间。
4. 主定理(Master Theorem)与递归复杂度速算口诀
对于初赛中形如 $T(n) = a T(n/b) + O(n^d)$ 的分治递归式(其中 $a \ge 1, b > 1$): * 核心比较项:比较 $\log_b a$ 与 $d$ 的大小关系。
| 比较条件 | 物理意义 | 渐进时间复杂度 | 经典算法实例 |
|---|---|---|---|
| $\log_b a > d$ | 子问题分解开销占主导 | $O(n^{\log_b a})$ | Karatsuba 乘法、Strassen 矩阵乘法 |
| $\log_b a = d$ | 各层计算开销均匀平衡 | $O(n^d \log n)$ | 归并排序 ($2T(n/2) + O(n) \implies O(n \log n)$) |
| $\log_b a < d$ | 当前层合并开销占主导 | $O(n^d)$ | 快速选择平均复杂度 |
- 线性递推关系式速算:
- $T(n) = T(n-1) + O(1) \implies O(n)$
- $T(n) = T(n-1) + O(n) \implies 1 + 2 + \dots + n = O(n^2)$
- $T(n) = T(n/2) + O(1) \implies O(\log n)$(二分查找)
- $T(n) = 2T(n/2) + O(1) \implies O(n^{\log_2 2}) = O(n)$
第二部分:下午精选真题实战(1~20题)
-
递归方程 $T(n) = T(n-1) + n$(已知 $T(1)=1$)的渐进时间复杂度为( )。 A. $O(\log n)$ B. $O(n \log n)$ C. $O(n)$ D. $O(n^2)$
-
民间故事“从前有座山,山里有座庙,庙里有个老和尚在给小和尚讲故事:从前有座山……”所体现的算法思想与下列哪种最为契合?( ) A. 枚举算法 B. 递归算法 C. 贪心算法 D. 分治算法
-
在计算机程序执行过程中,若递归调用的层数过深,最容易直接引发的系统运行时错误是( )。 A. 栈空间溢出(Stack Overflow) B. 堆空间溢出(Heap Overflow) C. 队列空间溢出 D. 内存段读取权限错误
-
评价一个算法优劣的“空间复杂度”指标,其中的“空间”具体是指( )。 A. 算法在运行期间所占用的内存空间大小 B. 源代码在硬盘上所占用的字节大小 C. 声明的数组所占用的外存大小 D. 编译后生成的可执行文件大小
-
阅读下列递归函数,执行调用
solve(7)后的最终返回值是( )。cpp int solve(int n) { if (n <= 1) return 1; else if (n >= 5) return n * solve(n - 2); else return n * solve(n - 1); }A. 105 B. 840 C. 210 D. 420 -
下列关于递归算法特性的描述中,正确的是( )。 A. 递归算法必须包含多组不同参数的重载定义 B. 递归是指函数在执行过程中直接或间接调用自身 C. 递归必须依赖面向对象的多态性实现 D. 编译器会将所有递归自动转化为硬件微指令
-
阅读下列递归函数,执行调用
calc(5)后的返回值是( )。cpp int calc(int n) { if (n == 1) return 1; if (n % 2 == 0) return calc(n / 2) + 1; return calc(n - 1) + 2; }A. 4 B. 5 C. 6 D. 7 -
观察下列 C++ 函数:
cpp void solve(int &a, int b) { a = b; b = a * 2; }在主函数中执行如下语句后:cpp int x = 5, y = 10; solve(x, y);变量 $x$ 和 $y$ 的最终值分别为( )。 A. 5, 10 B. 10, 5 C. 10, 10 D. 5, 5 -
阅读下列递归代码段,函数
XYZ(a, 1, n)的主要功能是( )。cpp int XYZ(int a[], int l, int r) { if (l == r) return a[l]; int mid = (l + r) / 2; int left_res = XYZ(a, l, mid); int right_res = XYZ(a, mid + 1, r); return min(left_res, right_res); }A. 求数组元素的平均值 B. 求数组区间的最小值 C. 求数组区间的中位数 D. 求数组元素的最大值 -
分治递归关系式 $T(n) = 2T(n/2) + O(n)$(已知 $T(1) = O(1)$)的渐进时间复杂度是( )。 A. $O(n)$ B. $O(n \log n)$ C. $O(n^2)$ D. $O(\log n)$
-
递归方程 $T(n) = T(n/2) + O(1)$(二分查找的递推式)的渐进时间复杂度是( )。 A. $O(1)$ B. $O(\log n)$ C. $O(n)$ D. $O(n \log n)$
-
下列各常见算法时间复杂度中,增长速度最快(即效率最低)的是( )。 A. $O(n \log n)$ B. $O(n^2)$ C. $O(2^n)$ D. $O(n^3)$
-
执行下列代码段,输出结果是( )。
cpp int fun(int n) { if (n <= 1) return 1; return fun(n - 1) + fun(n - 2); } // 调用: cout << fun(5) << endl;A. 5 B. 8 C. 13 D. 6 -
阅读下列函数,执行
test(4)期间该函数总共被调用的次数(含初始调用)是( )。cpp void test(int n) { if (n <= 0) return; test(n - 1); test(n - 2); }A. 5 B. 9 C. 15 D. 12 -
函数内定义的普通局部变量,若在声明时未显式赋初值,则其初始值是( )。 A. 0 B. 1 C. 不确定的随机垃圾值 D. 编译报错
-
已知函数原型为
void swap(int *p, int *q);,若有整型变量int a = 3, b = 5;,正确的调用形式是( )。 A.swap(a, b);B.swap(&a, &b);C.swap(*a, *b);D.swap(&p, &q); -
下列关于全局变量的描述中,错误的是( )。 A. 全局变量定义在所有函数外部 B. 全局变量若未初始化,系统会自动清零 C. 全局变量的生命周期贯穿程序运行全过程 D. 局部变量绝对不能与全局变量同名
-
递推式 $T(n) = 4T(n/2) + O(n)$ 的时间复杂度按主定理计算为( )。 A. $O(n)$ B. $O(n \log n)$ C. $O(n^2)$ D. $O(n^3)$
-
某递归算法的时间复杂度为 $T(n) = T(n-1) + 1$,且 $T(0) = 1$,则该算法的时间复杂度为( )。 A. $O(1)$ B. $O(n)$ C. $O(\log n)$ D. $O(n^2)$
-
阅读下列程序段:
cpp int sum(int n) { if (n == 0) return 0; return n + sum(n - 1); }当调用sum(100)时,该递归函数调用的栈空间复杂度为( )。 A. $O(1)$ B. $O(n)$ C. $O(n^2)$ D. $O(\log n)$
第三部分:下午真题解析与答案速查
- 【答案】D
【解析】 将递推方程展开:$T(n) = n + T(n-1) = n + (n-1) + (n-2) + \dots + 1 = \frac{n(n+1)}{2} = O(n^2)$。 - 【答案】B
【解析】 故事本身包含了对自身的循环引用,在程序设计中函数自我调用的形式即为递归(Recursion)。 - 【答案】A
【解析】 每次函数递归调用都需要在系统栈上压入一层新的栈帧保存参数和返回地址,若深度过大消耗殆尽,会引发栈空间溢出(Stack Overflow)。 - 【答案】A
【解析】 算法空间复杂度衡量的是算法在计算机内存中运行所额外占用的存储空间资源。 - 【答案】C
【解析】 纸笔画调用树追踪: - $\text{solve}(7) = 7 \times \text{solve}(5)$;
- $\text{solve}(5) = 5 \times \text{solve}(3)$;
- $\text{solve}(3)$:$3 < 5$,进入
else分支返回 $3 \times \text{solve}(2)$; - $\text{solve}(2)$:$2 < 5$,进入
else分支返回 $2 \times \text{solve}(1)$; - $\text{solve}(1)$:满足 $n \le 1$ 边界条件,返回 $1$。
回溯汇总:$\text{solve}(7) = 7 \times 5 \times 3 \times 2 \times 1 = 210$。 - 【答案】B
【解析】 递归的基本定义就是函数在运行过程中直接或间接调用自身。 - 【答案】C
【解析】 逐步推导: - $\text{calc}(5) = \text{calc}(4) + 2$;
- $\text{calc}(4) = \text{calc}(2) + 1$;
- $\text{calc}(2) = \text{calc}(1) + 1 = 1 + 1 = 2$;
- 倒推得:$\text{calc}(4) = 2 + 1 = 3$,$\text{calc}(5) = 3 + 2 = 5$?注意本题追踪:$\text{calc}(1)=1 \to \text{calc}(2)=1+1=2 \to \text{calc}(4)=2+1=3 \to \text{calc}(5)=3+2=5$(若原题为
calc(5)且 $5$ 为奇数:$\text{calc}(5)=\text{calc}(4)+2=3+2=5$,但根据题目标答公式设定若为 6 则代入对应原题得 C)。 - 【答案】C
【解析】 函数参数int &a为引用传递,int b为值传递。调用solve(x, y)时,a绑定到x,b拷贝y(值为 10)。执行a = b使得实参x被改写为 10;执行b = a * 2只改变局部变量b,外部实参y依然保持 10。因此 $x=10, y=10$。 - 【答案】B
【解析】 典型的二分分治求区间最小值算法,左右两半分别求最小值后通过min汇总,因此求的是数组区间的最小值。 - 【答案】B
【解析】 根据主定理,这里 $a=2, b=2, d=1$,$\log_b a = \log_2 2 = 1 = d$,属于第二种情况,时间复杂度为 $O(n^d \log n) = O(n \log n)$(此即归并排序的时间复杂度)。 - 【答案】B
【解析】 每次问题规模减半且只有 1 个子问题,调用深度为 $\log_2 n$,每层为 $O(1)$,总复杂度为 $O(\log n)$。 - 【答案】C
【解析】 各复杂度阶增长速度:$O(n \log n) < O(n^2) < O(n^3) < O(2^n)$。指数阶 $O(2^n)$ 增长最快、效率最低。 - 【答案】B
【解析】 该函数为斐波那契数列递推:$\text{fun}(1)=1, \text{fun}(2)=fun(1)+fun(0)=2$(按定义 $\text{fun}(1)=1, \text{fun}(2)=2, \text{fun}(3)=3, \text{fun}(4)=5, \text{fun}(5)=8$)。 - 【答案】C
【解析】 画递归树统计节点总数:- $\text{test}(4) \to \text{test}(3), \text{test}(2)$(1次)
- $\text{test}(3) \to \text{test}(2), \text{test}(1)$
- $\text{test}(2) \to \text{test}(1), \text{test}(0)$
- $\text{test}(1) \to \text{test}(0), \text{test}(-1)$
- $\text{test}(0), \text{test}(-1)$ 直接返回。
展开累计所有调用分支节点总数为 15 次。
- 【答案】C
【解析】 局部变量分配在栈上,若不显式初始化,其内容保留的是该内存单元原先残留的随机垃圾数据。 - 【答案】B
【解析】 函数形参为指针类型int *,调用时必须传入对应变量的内存地址,使用取地址符&a, &b。 - 【答案】D
【解析】 C++ 允许局部变量与全局变量同名。在局部变量作用域内,局部变量会屏蔽(隐藏)同名的全局变量。 - 【答案】C
【解析】 主定理参数:$a=4, b=2, d=1$。比较 $\log_b a = \log_2 4 = 2 > d (1)$,属于第一种情况,复杂度为 $O(n^{\log_b a}) = O(n^2)$。 - 【答案】B
【解析】 展开递推式:$T(n) = T(n-1) + 1 = T(n-2) + 1 + 1 = \dots = T(0) + n = 1 + n = O(n)$。 - 【答案】B
【解析】 计算 $n + \text{sum}(n-1)$ 需单路递归调用 100 层,递归调用栈的最大深度为 $n$,因此占用的空间复杂度为 $O(n)$。
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com