第 14 届蓝桥杯 C++ 青少组省赛中 / 高级组真题解析

一、选择题
第 1 题

题目:C++ 中,bool 类型的变量占用字节数为( )。


A. 1
B. 2
C. 3
D. 4
答案:A
解析
C++ 标准规定,bool类型至少占用 1 字节(1 byte),用于存储true(非 0)或false(0)。尽管逻辑上只需 1 位,但内存分配以字节为最小单位,因此选 A。
考点:C++ 基础数据类型的内存占用。
重点:掌握boolcharintdouble等类型的字节数(如char占 1 字节,int通常占 4 字节)。
教学方案:通过对比表格讲解数据类型,强调bool的特殊性(1 字节而非 1 位),结合内存对齐原则理解。

第 2 题

题目:以下关于 C++ 结构体的说法,正确的是( )。
A. 结构体中只能包含成员变量,不能包含成员函数
B. 结构体不能从另一个结构体继承
C. 结构体里面可以包含静态成员变量
D. 结构体里面不能包含构造函数
答案:C
解析

  • A 错误:结构体可包含成员函数(与类的区别仅在于默认访问权限为public)。
  • B 错误:结构体支持继承(语法与类相同,默认public继承)。
  • C 正确:结构体允许静态成员变量(属于类型本身,而非实例)。
  • D 错误:结构体可定义构造函数,用于初始化成员。
    考点:结构体与类的特性对比。
    重点:理解结构体的成员类型(变量、函数、静态成员、构造函数),区分结构体与类的默认访问权限。
    教学方案:编写包含成员函数和构造函数的结构体示例,演示继承语法,对比类与结构体的异同。
第 3 题

题目:设只含根结点的二叉树高度为 1,共有 62 个结点的完全二叉树的高度为( )。
A. 4
B. 5
C. 6
D. 7
答案:C
解析
完全二叉树高度h满足:

  • h-1层是满二叉树,结点数为2^(h-1)-1
  • h层至少 1 个结点,最多2^(h-1)个结点。
    计算:
  • h=5时,前 4 层结点数为2^4-1=15,总结点数最多15+8=23(<62,不满足);
  • h=6时,前 5 层结点数为2^5-1=31,总结点数最多31+32=63(≥62,满足)。
    故高度为 6,选 C。
    考点:完全二叉树的结点数与高度关系。
    重点:掌握公式2^(h-1) ≤ 结点数 ≤ 2^h - 1,通过不等式求解高度。
    教学方案:画图演示满二叉树与完全二叉树的结构,推导高度计算公式,通过例题强化计算。
第 4 题

题目:以下关于数组的说法,不正确的是( )。
A. 数组中所有元素的类型必须都相同
B. 数组中各元素在内存中是顺序存放的
C. 数组最后一个元素的索引是数组的长度
D. 数组名的第一个字符可以是下划线
答案:C
解析

  • A 正确:数组元素类型必须统一(如int arr[5]所有元素均为int)。
  • B 正确:数组在内存中连续存储,元素地址递增。
  • C 错误:索引从 0 开始,最后一个元素索引为长度-1(如长度 5 的数组索引 0~4)。
  • D 正确:数组名是标识符,允许以下划线开头(如_arr)。
    考点:数组的基本特性。
    重点:强调索引越界风险,区分数组长度与最大索引(长度 - 1)。
    教学方案:通过代码示例演示数组定义、访问,故意写出越界代码(如arr[5]对长度 5 的数组),观察错误现象。
第 5 题

题目:执行以下代码,输出结果是( )。

cpp

#include <iostream>  
using namespace std;  
int f(int k) {  
    if (k == 1) return 3;  
    return 2 * f(k - 1) + 1;  
}  
int main() {  
    int n = 6;  
    cout << f(n);  
    return 0;  
}  

A. 127
B. 97
C. 63
D. 126
答案:A
解析
递归函数递推关系:

  • 基例:f(1)=3
  • 递推:f(k)=2*f(k-1)+1
    展开计算:
  • f(2)=2×3+1=7
  • f(3)=2×7+1=15
  • f(4)=2×15+1=31
  • f(5)=2×31+1=63
  • f(6)=2×63+1=127
    考点:递归函数的递推计算。
    重点:理解递归终止条件与递推公式,可转化为等比数列(通项公式:f(k)=2^(k+1)-1)。
    教学方案:用递归展开法逐步计算,引入数学归纳法推导通项公式,避免深层递归导致栈溢出。
二、编程题
第 6 题:特殊运算符

题目描述
定义运算符 “>>>N” 为提取 N 的前两位数字(如 257→25,182→18),计算 N - (>>>N)。
输入:三位数 N(100<N<1000)。
输出:N 减去前两位的结果。
样例输入:257 → 输出 232(257-25=232)。

答案代码

cpp

#include <iostream>  
using namespace std;  
int main() {  
    int n;  
    cin >> n;  
    int first_two = n / 10; // 提取前两位(如257/10=25)  
    cout << n - first_two << endl;  
    return 0;  
}  

解析
三位数的前两位可通过整数除法n//10得到(如 933//10=93),直接计算差值即可。
考点:数字处理(整数除法提取高位)。
重点:掌握//%的用法,明确三位数的结构(百位 ×100 + 十位 ×10 + 个位)。
教学方案:通过分解数字的各位(百位、十位、个位)演示n//100n//10%10n%10,强调整数除法的应用。

第 7 题:四叶玫瑰数

题目描述
找出四位数中各位数字的四次方之和等于自身的数(如 1634=1⁴+6⁴+3⁴+4⁴),输出 N~M 范围内的数。
输入:N 和 M(1≤N≤M≤1e6)。
输出:按从小到大顺序的四叶玫瑰数。
样例输入:1234 2345 → 输出 1634。

答案思路

  1. 仅枚举四位数(1000≤num≤9999),减少计算量;
  2. 分解各位数字:千位a=num/1000,百位b=num/100%10,十位c=num/10%10,个位d=num%10
  3. 计算四次方和,若等于原数则输出。

代码框架

cpp

#include <iostream>  
using namespace std;  
bool is_rose(int num) {  
    int a = num / 1000, b = num / 100 % 10, c = num / 10 % 10, d = num % 10;  
    return a*a*a*a + b*b*b*b + c*c*c*c + d*d*d*d == num;  
}  
int main() {  
    int n, m;  
    cin >> n >> m;  
    for (int i = max(n, 1000); i <= min(m, 9999); i++) {  
        if (is_rose(i)) cout << i << " ";  
    }  
    return 0;  
}  

考点:枚举算法与数字分解。
重点:限定枚举范围(仅四位数),优化循环条件,避免无效计算(如处理 N<1000 或 M>9999 的情况)。
教学方案:讲解 “四叶玫瑰数” 的数学定义,演示数字分解方法,强调提前过滤非四位数以提高效率。

第 8 题:质因数的个数

题目描述
统计 N~M 之间每个数的质因数个数(重复质因数算多个,如 8=2×2×2,个数为 3),求最大值。
输入:N 和 M(1≤N≤M≤1e7)。
输出:最大质因数个数。
样例输入:6 10 → 输出 3(8 的质因数个数为 3)。

答案思路

  1. 对每个数num进行质因数分解:从 2 到√num 试除,统计每个质因数的次数;
  2. 若试除后num>1,说明剩余部分是质数,次数加 1;
  3. 遍历 N~M,记录最大次数。

代码核心

cpp

int count_prime_factors(int num) {  
    int count = 0;  
    for (int i = 2; i * i <= num; i++) {  
        while (num % i == 0) { // 统计i的次数  
            count++;  
            num /= i;  
        }  
    }  
    if (num > 1) count++; // 处理剩余质数(如7、13等)  
    return count;  
}  

考点:质因数分解与贪心统计。
重点:试除法分解质因数,区分质因数的 “种类” 与 “个数”(本题统计个数,包括重复)。
教学方案:通过示例(如 12=2²×3¹,个数 2+1=3)讲解质因数个数的定义,演示试除过程,强调从小到大试除以确保质因数。

第 9 题:最大的矩形纸片

题目描述
在直方图中找最大矩形面积(高度数组 [3,2,1,4,5,2] 的最大面积为 8)。
输入:N(列数)和高度数组。
输出:最大矩形面积。

答案思路
使用单调栈算法

  1. 维护一个单调递增栈,存储索引,对应高度递增;
  2. 遍历每个高度,找到左右两边第一个比它小的位置,计算宽度right - left - 1,面积 = 高度 × 宽度;
  3. 处理边界条件(数组末尾加 0,确保栈中元素全部弹出)。

代码框架

cpp

#include <iostream>  
#include <stack>  
using namespace std;  
long long max_area(int n, int* heights) {  
    stack<int> st;  
    long long res = 0;  
    for (int i = 0; i <= n; i++) { // 末尾加0,处理所有元素  
        while (!st.empty() && (i == n || heights[st.top()] >= heights[i])) {  
            int h = heights[st.top()]; st.pop();  
            int w = st.empty() ? i : i - st.top() - 1;  
            res = max(res, (long long)h * w);  
        }  
        st.push(i);  
    }  
    return res;  
}  

考点:直方图最大矩形面积(单调栈算法)。
重点:理解单调栈的作用(快速找到左右边界),处理数据类型溢出(使用long long)。
教学方案:通过直方图画图演示单调栈的工作流程,解释每个步骤的意义,对比暴力法与单调栈的时间复杂度(O (n) vs O (n²))。

第 10 题:数字游戏

题目描述
交替调整最小数到第二小、最大数到第二大,直到不同数少于 3 个,输出调整次数、最终最小和最大值。
输入:数组。
输出:次数、最终最小值、最大值。
样例输入:1 3 4 2 → 调整 2 次,结果 2 2 3。

答案思路

  1. 每次操作后排序数组,统计不同数的数量;
  2. 第奇数次操作:将所有最小数改为第二小数;
  3. 第偶数次操作:将所有最大数改为第二大数;
  4. 直到不同数≤2 时终止。

代码核心

cpp

#include <iostream>  
#include <vector>  
#include <algorithm>  
using namespace std;  
int main() {  
    int n;  
    vector<int> nums;  
    cin >> n >> nums;  
    int count = 0;  
    bool is_min_turn = true; // 第一次调整最小数  
    while (true) {  
        sort(nums.begin(), nums.end());  
        // 统计不同数  
        int unique = 1;  
        for (int i = 1; i < n; i++) {  
            if (nums[i] != nums[i-1]) unique++;  
        }  
        if (unique < 3) break;  
        if (is_min_turn) {  
            int second_min = nums[1];  
            for (int i = 0; i < n; i++) {  
                if (nums[i] == nums[0]) nums[i] = second_min;  
            }  
        } else {  
            int second_max = nums[n-2];  
            for (int i = 0; i < n; i++) {  
                if (nums[i] == nums[n-1]) nums[i] = second_max;  
            }  
        }  
        count++;  
        is_min_turn = !is_min_turn;  
    }  
    sort(nums.begin(), nums.end());  
    cout << count << " " << nums[0] << " " << nums.back() << endl;  
    return 0;  
}  

考点:模拟算法与排序。
重点:每次操作后排序,正确识别第二小 / 第二大数,处理边界情况(如所有数相同)。
教学方案:通过示例演示调整过程,强调排序的重要性,讲解如何统计不同数的数量(遍历或使用集合)。

第 11 题:活动人数

题目描述
树状结构中,选某部门则不能选直接下级,求最大人数(树形动态规划)。
输入:部门数 N,每个部门的上级 F、编号 S、人数 C。
输出:最大人数。
样例输入:6 个部门,输出 11(选部门 1、4、5、6,人数 2+3+2+4=11)。

答案思路
每个节点有两种状态:

  • dp[u][1]:选节点 u 时,最大人数(等于 u 的人数 + 所有子节点不选的最大值);
  • dp[u][0]:不选节点 u 时,最大人数(等于所有子节点选或不选的最大值之和)。
    通过深度优先搜索(DFS)递归计算每个节点的状态。

代码框架

cpp

#include <iostream>  
#include <vector>  
using namespace std;  
struct Node {  
    int c;  
    vector<int> children;  
};  
Node nodes[100001];  
int dp[100001][2]; // dp[u][1]选,dp[u][0]不选  

void dfs(int u) {  
    dp[u][1] = nodes[u].c; // 选当前节点,初始化为自身人数  
    for (int v : nodes[u].children) {  
        dfs(v);  
        dp[u][1] += dp[v][0]; // 子节点不能选  
        dp[u][0] += max(dp[v][0], dp[v][1]); // 子节点可选或不选  
    }  
}  

int main() {  
    int n;  
    cin >> n;  
    for (int i = 1; i <= n; i++) {  
        int f, s, c;  
        cin >> f >> s >> c;  
        nodes[s].c = c;  
        if (f != 0) nodes[f].children.push_back(s); // 构建树结构  
    }  
    // 找根节点(上级为0的节点)  
    int root = 0;  
    for (int i = 1; i <= n; i++) {  
        if (nodes[i].children.size() > 0 && (root == 0 || ...)) {  
            // 实际应遍历找到f=0的s  
            // 正确方法:记录每个节点的父节点,找父节点为0的节点  
        }  
        // 简化:假设根节点是1(需根据输入正确查找)  
        root = 1; // 实际需遍历所有节点,找到f=0对应的s  
    }  
    dfs(root);  
    cout << max(dp[root][0], dp[root][1]) << endl;  
    return 0;  
}  

考点:树形动态规划(树上的选与不选问题)。
重点:树的存储(邻接表),状态转移方程的推导,根节点的确定(上级为 0 的节点)。
教学方案:讲解树的基本概念,演示状态转移方程的推导过程,通过样例分析选与不选的决策对结果的影响,强调递归 DFS 的实现。

详细教学方案

一、选择题模块
  1. 数据类型与内存

    • 对比boolcharint等类型的字节数,通过代码sizeof(bool)验证。
    • 讲解内存对齐原则,解释为何bool占 1 字节而非 1 位。
  2. 结构体与类

    • 编写包含成员函数、构造函数、静态成员的结构体示例,演示继承语法(struct B : public A)。
    • 对比结构体与类的默认访问权限(public vs private)。
  3. 二叉树性质

    • 画图演示满二叉树与完全二叉树,推导高度计算公式h = floor(log2(n)) + 1
    • 通过练习题(如结点数 30、63 的高度)强化计算。
  4. 数组基础

    • 演示数组定义、初始化、越界访问,用调试工具观察内存布局。
    • 强调索引从 0 开始,通过错误案例(如访问arr[len])加深印象。
  5. 递归函数

    • 用递归展开法计算第 5 题,引入数学归纳法推导通项公式f(k)=2^(k+1)-1
    • 讲解递归与迭代的转换,避免栈溢出(如限制递归深度)。
二、编程题模块
  1. 数字处理(第 6 题)

    • 讲解整数除法//和取余%的用法,分解三位数的百位、十位、个位。
    • 设计变式题:提取前两位(三位数)、前三位(四位数),计算差值。
  2. 枚举算法(第 7 题)

    • 限定枚举范围(四位数),避免无效循环(如 N=500 时从 1000 开始枚举)。
    • 优化数字分解:用数学公式快速获取各位数字,减少计算量。
  3. 质因数分解(第 8 题)

    • 演示试除法分解质因数,强调从小到大试除确保质因数(如先除 2,再除 3,直到√num)。
    • 区分质因数的 “个数” 与 “种类”(本题统计个数,包含重复)。
  4. 单调栈算法(第 9 题)

    • 通过直方图动画演示单调栈的工作流程,解释每个元素的左右边界如何确定。
    • 对比暴力法(O (n²))与单调栈(O (n))的效率,强调算法优化的重要性。
  5. 模拟与排序(第 10 题)

    • 通过示例表格记录每次调整后的数组状态,演示排序的作用(快速找到最小 / 最大值)。
    • 处理边界情况:如所有数相同(直接输出 0 次),或只有两种不同数(无需调整)。
  6. 树形动态规划(第 11 题)

    • 讲解树的存储方式(邻接表),如何构建树结构(根据输入的上下级关系)。
    • 推导状态转移方程:选当前节点则子节点不能选,不选则子节点可选或不选,取最大值。
    • 通过样例分析递归过程,强调根节点的正确查找(上级为 0 的节点)。
三、实战训练
  • 选择题:设计 10 道同类题目,涵盖数据类型、结构体、二叉树、数组、递归等考点,限时 5 分钟完成。
  • 编程题
    • 第 6 题变式:处理四位数,提取前三位,计算差值。
    • 第 8 题优化:预处理质数表,加速质因数分解(适用于大数据范围)。
    • 第 11 题扩展:处理森林(多棵树),求所有树的最大人数之和。
  • 调试技巧
    • 学会使用断点调试,观察递归过程或循环变量变化。
    • 针对超时问题,分析算法时间复杂度,优化循环条件或选择更高效的算法(如单调栈替代双重循环)。

通过以上教学方案,学生可系统掌握 C++ 基础、算法思维和编程技巧,提升解决竞赛题目的能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值