GESP 2026年9月 C++ 一至四级真题分析:模板退场之后,考的是现场建模
点击上方蓝字关注我们

2026 年 9 月 12 日,CCF GESP 第 15 次编程能力等级认证举行。
一至四级的卷面结构自 2023 年首考以来没有变过——15 道单选(每题 2 分)+ 10 道判断(每题 2 分)+ 2 道编程(每题 25 分),共 27 题、100 分。客观题与编程题各占一半分值,这个比例在四个级别上完全一致。

把 6 月与 9 月的编程题并排看,最直观的感受是题面换了包装。6 月那场被普遍认为偏"宽":二级考完全平方数计数,四级考扫雷与 BMI,题目在各家讲义里出镜率很高,练过模板的考生容易提前完成。9 月的八道编程题几乎看不到可以直接套用的原题,几道题还在边界条件上埋了钩子。
整体上可以归纳为三点变化:
1、模板题退场,题意翻译成为第一道坎。题目不再考查"认不认得出模型",而是考查能不能把一段生活化的描述准确翻译成循环、分支和递推式。
2、边界条件成为第一失分点。一级麦粒题的数据类型、三级分割字符串的空行、四级汉诺塔的移动方向限制——题面不会提示,样例也未必"露馅"。
3、客观题开始重"手跑代码"。把 for的条件写成赋值语句、短路求值下哪一句不会执行、值传递与引用传递的结果差异,都需要在脑子里逐行执行程序才能判断。

知识模块分布

综合题按主要考点归类,只计一次,合计 25 题。
编程题 T1 · 新龟兔赛跑
思路分步
1.算兔子的跑步时间:起点到终点固定 1000.0,除以兔子速度得到 1000.0 / v。
2.加上睡觉时间:兔子总时间 rt = 1000.0 / v + t2。这一步最容易漏。
3.三路比较:rt < t1 输出 rabbit;rt > t1 输出 turtle;相等输出 tie。
4.按格式输出 rt,保留两位小数。
三个关键点:
距离写成 1000.0,不要写 1000。只要参与运算的两个操作数都是整型,除法的结果就会被截断成整数,写出小数点是最省心的写法。
分支必须写全小于、大于、等于三种情况,漏掉平局分支会丢分。
两位小数必须显式指定。cout 直接输出 21.0 会变成 21,需要 fixed << setprecision(2) 或 printf("%.2f")。
编程题 T2 · 棋盘上的奖赏
思路分步
1.第 i 格的麦粒数是 2i−1,所以前 n 格总数是等比数列求和:1 + 2 + 4 + … + 2n−1 = 2n − 1。
2.一级更推荐用循环逐格累加:用 f 保存"当前这一格有多少粒"(初值 1),用 ans 保存"目前总共有多少粒"(初值 0)。
3.循环 n 次,每次先 ans += f,再 f *= 2。顺序反了会多算一格。
这道题为什么难。难度增加在于,最近几次的一级编程题T2,考查的都是一组数值的累加,但是这次变成了累加 + 累乘,累加的数字需要我们先用累乘算出来,难度提升。这个题型在正式课中oj的C1A-12-01有讲过类似例题,同学们可以再去挑战一下。
客观题亮点
复合赋值与自增的求值顺序
int b = 8;
b *= 2 + 1; // 24:先算 2 + 1 = 3,再乘
int b = 8;
++b *= 2 + 1; // 27:++b 先自增到 9,再算 9 * 3
第二个例子最容易错——右操作数是整个表达式 2 + 1,而不是单独的 2。
负号与取余
4 + -2 * 3 → −2(先乘后加)
2 * -2 % 3 → −1(乘号与 % 同级、从左到右;C++ 中负数取余结果为负)
2 % -2 * 3 → 0
2 * (-2 % 3) → −4
整数除法截断
a = 8, b = 10 时:a % b = 8;a * 1 / b = 0;a * 1.0 / b = 0.8。这是本次一级客观题里出现频率最高的失分点。
其他高频细节
for (i = 0; i < 10; i++) 循环结束后 i 的值是 10,不是 9——循环条件不成立才退出。
取数位模板:取从右往左第 M 位 = N / 10(M−1) % 10。
第 1 题仍是"时事背景 + 计算机基础"的组合,本次落点是世界人形机器人运动会与 IDE 的功能边界:IDE 只负责编写、编译、调试代码,直接控制电机转动的是编译后的程序加硬件驱动。
另一道基础题考计算机四个时代的划分依据——核心元器件(电子管 → 晶体管 → 中小规模集成电路 → 大规模/超大规模集成电路),"运算速度"是结果而不是划分依据。
与 3 月、6 月的难度对比

一级的知识范围整体稳定,但本次有两处新面孔:一是浮点数的比较与格式化输出(且要求三路分支写全),二是把"依据数据范围选类型"直接埋进了题面。这两点在过去的一级卷里都很少见。
把 if / else if / else 的三路处理写完整,能覆盖大小比较、区间判断、奇偶判断、时间判断。
熟练使用 for 与 while 完成循环计数、连续求和、连续求积,并能在一次循环里同时更新多个变量。
分清整数除法与浮点除法;掌握 fixed << setprecision(n) 与 printf("%.2f") 两种输出写法。
牢记取数位模板 N / 10(M−1) % 10,并能逐行"手跑"一段简单程序写出结果。
看到数据范围先估算答案上界,再决定用 int 还是 long long。
算术式写成 1000 / v,参与运算的整数导致除法被截断。
漏掉平局分支,只写了"谁快谁赢"两种结果。
输出 21.0 而不是 21.00——忘记设置输出格式。
累加与翻倍的先后顺序写反,结果多算一格。
循环结束后变量的最终值判断错误(把 10 写成 9)。


知识模块分布

编程题 T1 · 直角三角形
思路分步
1.先处理两种极端情况:如果第 1 项就已经超过上限,直接输出 1;如果第 2 项超过上限,直接输出 2。
2.否则用两个变量a、b保存相邻两项,循环生成下一项:c = sqrt(a \* a + b \* b)。
3.生成之后两项一起前移:a = b; b = c;,同时把项号 k 加一。
4.循环条件是 b <= m——只要还没超过上限就继续。跳出循环时 b 就是第一个严格超过上限的项,输出此时的项号 k。
样例验算:3.0、4.0 → 第 3 项 5.0 → 第 4 项 √(4² + 5²) = 6.403 → 第 5 项 √(5² + 6.403²) ≈ 8.12 → 第 6 项 √(6.403² + 8.12²) ≈ 10.34 > 10.0,所以答案是 6。
这道题为什么难。这道题实际上核心考的是递推,如果练习不够的话,用三个变量来实现递推还是有难度。同学们需要再练习递推类的题型。
编程题 T2 · 字符变换
思路分步
1.用双层循环遍历 8 行 16 列:外层 i 从 1 到 8,内层 j 从 1 到 16。
2.把两维坐标换算成一维编号:k = (i − 1) \* 16 + j。这是本题的核心——编号是从 1 开始、按行连续排的。
3.如果 k 等于三个输入编号之一,输出 char(k);否则输出 *。
4.每输出完一行,补一个换行。
最容易搞反的一点:输入的三个正整数是格子编号,不是字符本身。ASCII 字符由编号转换得到——48 是字符 0,65 是字符 A,97 是字符 a。所以是 char(k),而不是把输入当成字符直接输出。
客观题亮点
多层循环的程序跟踪占比较高。要能算清内外层各执行多少次,并理解 break 与 continue 只影响当前所在的那一层循环。
类型转换与布尔运算。字符 '2' 参与算术时用的是它的 ASCII 码 50,不是数值 2;bool 参与运算会被当作 0 和 1;逻辑表达式存在短路求值——a || ++b 中若 a 已为真,++b 根本不会执行。
数学函数。出现 abs()、sqrt() 的实际应用,需要根据题意选对函数并设置正确的循环终止条件。
素数判断与并列条件的组合,以及与一级重合的取数位、循环步长类细节题。
与 3 月、6 月的难度对比

二级编程题的配置很稳定:一道"图形 / 计数",一道"字符处理"。本次两道题都无法直接套现成模板——《直角三角形》需要现场把"前两项的平方和开根号"翻译成递推关系,《字符变换》需要同时处理一维编号、二维坐标与 ASCII 字符三层对应关系。
熟练掌握多层分支结构,能处理多个条件的先后关系,并正确使用 &&、|| 与括号组合条件。
用多层循环打印图形:明确外层循环控制行、内层循环控制列,能完成矩形、三角形等字符图形输出。
掌握 ASCII 编码与类型转换,能在整数与字符之间互转,并应用到字符画、字符判断与字符输出中。
掌握多层循环的枚举与拆位:范围内计数、数位统计、因数判断、素数判断,以及在循环中求和、求积、更新最值。
会用 abs()、sqrt()、max()、min(),并能根据题意设置正确的循环终止条件。
项号差一:项号从 1 开始数,"第一个超过上限"是跳出循环时的项号,不是循环次数。
没有先把下一项存进临时变量就直接赋值,导致前两项被互相覆盖,递推结果全错。
把输入的编号当成字符直接输出,漏掉 char(k) 这一步转换。
一维编号算成 i * 16 + j(应为 (i − 1) * 16 + j),整体偏移一行。
画布每行结束忘记换行,或格子之间多输出了空格。
误判 break / continue 的作用范围,以为会影响外层循环。

知识模块分布
编程题 T1 · 公共二进制位
思路对比
常规做法:把每个数转换成二进制字符串或数组,再逐位对齐比较。这种做法步骤繁琐,很容易在下标对齐上出错,数据量一大还可能超时。
更优做法:先将题目给出的所有数字全部进行按位与运算,按位与的规则是“只有两边同时为 1的位才会保留 1”,将所有数字进行按位与之后,我们只需要结合正式课 C1A-13 与 C2A-02 的知识,剥离数字的二进制位,统计有几个 1 即可
为什么这题值得单独说:三级编程题这次把位运算放到了"要你自己写出来"的位置。6 月那道《加密》用的是密码本映射(数组 + ASCII),套路在各家讲义里出镜率很高;这次要现场想到"按位与求交集"这个模型,是从"读得懂位运算"到"写得出位运算"的一步跨越。
编程题 T2 · 分割字符串
思路分步
1.第一次遇到连续 1 个空格切一刀,对右边剩下的部分继续,第二次要连续 2 个空格,第 k 次要连续 k 个——所以循环变量 k 同时代表"轮次"和"本轮要几个空格":for (int k = 1; ; ++k)。
2.每轮用 string(k, ' ') 造出这把刀,用 s.find() 定位:找到就输出左半段 s.substr(0, pos),再把 s = s.substr(pos + k) 交回下一轮。只用掉 k 个空格,多出来的原地留在右侧开头,这一点是整题的关键。
3.find 找不到时返回的是 string::npos(不是 −1),这时 break 跳出;循环外还要把最后剩下的 s 单独输出一行。
三个必须处理的边界
1.整行读入。必须用 getline 完整读入整行。如果用 cin >> str,程序在第一个空格处就会停下,后面所有连续空格全部丢失,题意直接崩掉。
2.剩余空格要保留。消耗掉本轮的 k 个连续空格之后,右侧还剩下的空格不能丢掉,要保留下来作为下一段的"前导空格",否则下一轮的切分位置全错。
3.空段也要输出。如果某一轮切分出来的段是空字符串,仍然要输出一个空行,不能省略。这一条最容易漏——代码逻辑对了,却卡在这个空行上。
这道题真正考的是空格的定位。 前两级读字符串,空格是用来分隔单词的;从这道题开始,空格本身就是被操作的数据,必须 getline(cin, s) 整行读入。写成 cin >> s,第一个空格之后的全部内容当场丢失,后面逻辑再对也没用。
这道题的难点在于,最近几次三级的字符串编程题,几乎只是简单考察了字符串遍历、字符偏移、字符类型判断、大小写转化等基础字符操作,而这道题变成了综合性的字符串操作——第一次在三级中考察到这类字符串操作的组合模拟题,就给了很多同学一个下马威。可以预见的是,今后三级编程题中,这类结合模拟法的字符串操作题很可能不会少。相比我们课堂上讲的“单词分割”模板题,这道题还增加了“递增连续空格分割”的条件。如果纯手动模拟完成,代码会非常复杂且容易出错;但如果熟练掌握C++标准库中的字符串处理函数,效率会高很多,代码也会更优雅。
客观题亮点
位运算的分量最重
把 for 的条件改写成赋值语句:条件位置写成 i = 0,整个表达式的值是 0,判定为假,循环体一次也不执行。这道题专门检验赋值表达式与关系表达式的区分敏感度。
x = x & (x − 1) 消掉最低位的 1:用循环次数统计 2026 的二进制里有多少个 1。2026 = 11111101010₂,答案是 8。这个技巧在编程题里也用得上。
以 Linux 权限管理为背景的位掩码:用按位或 | 添加权限位,用按位与非 & ~ 精确清除某个权限位。命题情境很新,考的是位运算在工程里的真实用法。
多层位运算的优先级:逻辑非、位移、按位与、异或、按位或混在一行里,需要按优先级拆开逐层求值。
字符常量参与数值比较:判断一个数串能否是二进制、八进制、十进制或十六进制,做法是把数串里的最高位字符与 '1'、'7'、'9'、'F' 逐个比较。这里必须是 <= 而不是 <——写成严格小于,恰好落在边界上的数就会被判错。
两处极易失分的细节
sizeof 求一维数组长度时,配合 C++11 的基于范围的 for 循环使用。注意 for (int num : a) 里的 num 只是局部副本,改它不会影响原数组;必须写成 int &num 才能修改数组元素。判断题正是拿这句话出的题,官方答案是错。
判断题给的是 char str[4] = "GESP";,问"这样是否给 str[4] 分配了 5 个字节"。答案是否:数组只开了 4 个字节,而字符串常量 "GESP" 连同末尾的 \0 需要 5 个字节,这一行本身就会编译报错。最容易混淆的地方在于——写成 char str[] = "GESP";(方括号里留空)反而是合法的,编译器会自动分配 5 个字节。差别就在那个写死的 4 上。
压轴思维题
本次三级的压轴是选择题第 15 题,也是全卷唯一一道要"现场建模"的题:1000 缸酒里恰有 1 缸有毒,毒发需要 24 小时;总共给 48 小时,可以做两轮实验,每轮可以重新安排老鼠喝酒。每只老鼠身上恰好有三种可区分的结果——两轮都不喝这缸酒 / 第一轮喝 / 第二轮喝,分别对应"两轮结束后仍存活""24 小时死亡""48 小时死亡"。
三种状态相当于一位三进制信息,k 只老鼠最多区分 3k 种情况。36 = 729 < 1000,不够;37 = 2187 ≥ 1000,够用——答案是 7 只。官方给的选项为 A. 5、B. 7、C. 10、D. 9,正确答案是 B。这类题不考语法,考的是"能不能把实验安排抽象成一个编码方案"。
与 6 月的难度对比

如果这一级只复习一个专题,那就是位运算:&、|、^、~、<<、>>、x & (x−1)、位掩码用法、以及各运算符的优先级。
吃透原码、反码、补码的表示与转换,包括补码加法中最高位进位要循环加到最低位这类细节。
进制转换与数制合法性判定,能把十进制与二进制互转当作"第一语言"来用。
字符串处理要练到能处理边界:getline 整行读入、find 查找、下标推进、空段与连续空格的保留。
数组定义语法与 string 成员函数、会读流程图与程序填空。
用 cin >> 读含空格的整行字符串,连续空格被截断。
切分出空字符串时忘记输出空行,或把右侧剩余空格一并吃掉。
把赋值表达式 i = 0 误读成关系判断,得出"循环执行一次"的错误结论。
范围 for 写成 for (int num : a),改的是副本,原数组没变。
误以为 char str[4] = "GESP"; 会分配 5 个字节——4 个字节装不下带 \0 的 5 个字符,这行是编译错误。
位运算优先级判断错误,尤其是逻辑非与位移、按位与混用时。


知识模块分布
编程题 T1 · 新汉诺塔(单向循环)
题目描述

为什么经典公式失效
经典汉诺塔的 2n − 1 建立在"可以双向移动"的前提上:先把上面 n−1 个盘搬到 B,挪走底盘,再把 n−1 个盘搬到 C。一旦只能单向绕行,从 A 到 C 变成"隔一柱",那一组让路的盘就没法直接搬到目标柱旁边,路径长度整个变了。
解法:把目标分成两种状态
f[i]:把 i 个盘从一根柱移到相邻柱(例如 A → B)的最少步数;
g[i]:把 i 个盘从一根柱移到隔一柱(例如 A → C)的最少步数。
f[i] = 2 * g[i-1] + 1; // 移到相邻柱
g[i] = 2 * g[i-1] + f[i-1] + 2; // 移到隔一柱
// 边界:f[0] = g[0] = 0,答案 = g[n]
三步校验(与官方样例完全吻合):f[1] = 1、g[1] = 2;f[2] = 5、g[2] = 7;f[3] = 15、g[3] = 21。n = 1 时答案 2,n = 2 时答案 7,n = 3 时答案 21。
式子本身不足 15 行代码,真正的难点在于考场上能不能想到"按目标柱是否相邻拆成两个状态"——限制方向的汉诺塔变体,绝大多数考生此前从未见过。
编程题 T2 · 有序网格
两轮排序的规则演示
以 2 × 2 的网格为例:
4 1 1 4 1 3
2 3 → 2 3 → 2 4
每行升序 每列升序
第一轮把第 1 行排成 1 4、第 2 行排成 2 3;第二轮检查各列——第 1 列 1, 2 已有序,第 2 列 4, 3 需要交换,得到 1 3 / 2 4。
上例用于说明两轮排序的规则,非官方样例。
真正的考点
思路本身很直接(手写两个方向的冒泡排序即可),这道题考的是代码组织能力:把"给一行排序"和"给一列排序"抽象成同一个函数,在两个维度上复用。核心难点在于精准控制多层嵌套循环的下标,避免行列独立遍历时发生越界或行列混淆。
客观题亮点
指针与const
const int *p 是"指向常量的指针":p 自身可以改指向(p = &b 合法),但通过 *p不能修改它指向的值。另外一道题结合二维数组考数组指针 int (*p)[4] 的多层解引用 *(*(p + 1) + 2)——先定位到第 2 行,再取该行的第 3 个元素。
二维数组的内存布局
二维数组在内存中按行优先连续存储,a[i][j] 的指针等价写法是 *(*(a + i) + j)。例如 *(*(a + 1) + 0) 就是 a[1][0]。这类题要求把下标写法和指针偏移写法互相翻译。
复杂度估算
判断题直接给出了一段 for (i = 0; i < n; i++) 套 for (j = 1; j < n; j *= 2) 的代码,断言它"时间复杂度是 O(n²)",官方答案是错。内层增量是倍数乘法,j 从 1 倍增到 n 只跑约 log₂n 次,所以整体是 O(n log n)。这道题正是要拦住"看见两层循环就写 O(n²)"的直觉。
作用域与引用(一道题考三点)
int score = 60; // 全局变量
void update(int &score) { score += 5; } // 引用传递
int main() {
int score = 80; // 局部变量,遮蔽全局
update(score);
cout << score << " " << ::score; // 输出 85 60
return 0;
}
main 里的局部 score 是 80,而 update 接收的是引用,改的正是 main 里的那个变量,变成 85;::score 访问的是全局变量,仍然是 60。一道题同时考了作用域、引用传递与全局作用域解析符。
结构体的值传递 vs 引用传递
struct Device { int id; int state; };
void reset(Device d) { d.state = 0; } // 值传递:改的是副本
void start(Device &d) { d.state += 1; } // 引用传递:改的是本体
int main() {
Device d{7, 2};
reset(d); // 外面看不到变化
start(d); // state 由 2 变成 3
cout << d.id << " " << d.state; // 输出 7 3
return 0;
}
输出 7 3:reset 是值传递,函数内的修改不影响原变量;start 是引用传递,state 被改成 3,而 id 从未被修改,仍是 7。值传递与引用传递在同一张卷子里连考两道,命题信号已经很明确。
排序与文件异常
稳定插入排序的填空:升序插入时,把元素后移的条件必须是 a[j] > key。写成 a[j] >= key 会把相等元素也往后挪,破坏稳定性——差一个等号就错,这是本次四级最典型的细节题。同一个考点判断题里又考了一遍:题面说"移动元素的条件通常应为 a[j] >= key,这样能保证相等元素的相对顺序不变",官方答案是错。同一知识点连考两题,分量不言自明。
三种排序的说法辨析、带退出标志的冒泡填空,以及双层循环的时间复杂度。
文件流与异常处理:ifstream 读文件、ofstream 写文件、catch 的类型匹配——以往四级卷很少露面的这两块内容这次都上场了。
与 6 月的难度对比

四级是本次口碑起伏最大的级别,也是"区分度重构"最典型的样本:客观题的知识点覆盖面明显变宽,编程题从模板复现转向现场推导。真正拉开差距的就是《新汉诺塔》—能想到按目标柱是否相邻拆状态的考生是少数。
函数与三种参数传递:值传递、引用传递、指针传递的行为差异,以及默认参数、形参实参、变量作用域与全局遮蔽。
指针基础与二维数组的内存逻辑:*(*(a + i) + j) 与 a[i][j] 的等价关系,const 修饰位置的含义。
三种基础排序(冒泡、选择、插入)的手写实现、时间复杂度与稳定性判断;并且要会"变形"——按列排序、按自定义规则排序。
递推:模板是起点而不是终点,要能根据新约束现场推导递推式(限制方向的汉诺塔就是典型)。
二维数组的取值、作形参、行优先连续存储;以及文件流与异常处理的基本用法。
把 const int *p 误解为"指针本身不可修改",混淆 const int * 与 int * const。
分不清值传递与引用传递,以为函数内改了形参,外面就会变。
插入排序写成 a[j] >= key,破坏排序稳定性。
二维数组按列遍历时行列混淆,导致下标越界或结果错位。
只背了 2n − 1,遇到限制移动方向的变体就无从下手。
倍数增量(j *= 2)的循环复杂度算成 O(n²)。
一至四级的命题重心:从"认得出模型"到"现场翻译题意"
本次认证的编程题几乎全部换了题面包装,往期真题可以直接套用的比例明显下降。
三条贯穿全卷的规律
1.级别越高,知识板块越集中。一级的考点散在六个模块里,四级则被"指针函数 + 排序 + 文件异常"三块吃掉了 84%。这张表上的空白处,就是各级考纲的边界线。
2."读程序"统治客观题。一级的复合赋值与循环终值、二级的双层循环与类型转换、三级的位运算与数据编码、四级的指针与排序,绝大多数题目都要把代码在脑子里跑一遍才敢下结论;纯靠记忆就能答对的题只剩个位数。
3.边界条件成为第一失分点。一级麦粒的数据类型、三级分割字符串的空行、四级插入排序的一个等号——题面不提示,样例也未必"露馅",全靠平时有没有"自造刁钻数据"的习惯。
1、真题要刷,但刷完要复盘题面。做完一道题多问一句:这道题换一种包装,我还能认出来吗?只记住"这道题用 for 循环"是不够的。
2、建立自己的边界测试清单。空输入、0、1、最大值、全相同、只有一行或一列……写完代码先拿这些数据自测一遍,再交卷。本次三级与四级的失分,大多落在这里。
3、三级把位运算学扎实。按位与、按位或、异或、移位、x & (x−1),以及常见的位掩码用法。这次的分值分布已经说明了它的分量。
4、 四级以上不能只背模板。排序要会"变形"(按列排序、自定义规则),递推要会"现场推"(限制方向的汉诺塔)。模板是起点,不是终点。
各级"必须掌握"清单

这次一至四级的共同信号是——题目不难,细节很难。卷面考查的知识点都在考纲之内,没有超纲争议;拉开差距的是"能不能把题意准确翻译成代码"和"交付前有没有自己造数据验一遍"。这两件事都不靠刷题量堆出来,靠的是写完代码之后那几分钟的复查习惯。

本文以上内容为手动整理,若有误差可反馈小编,希望能帮助到大家!
版权声明
本文仅作者转发或者创作,不代表旺旺头条立场。
如有侵权请联系站长删除
旺旺头条




发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。