ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

GESP备考:考纲比题量更值钱,高频考点与真题思路全解析

GESP备考:考纲比题量更值钱,高频考点与真题思路全解析

简介:CCF编程能力等级认证(GESP)真题与知识点合集面向考生、编程教师及信息学竞赛爱好者,系统覆盖Scratch图形化1-4级、Python 1-8级与C++ 1-8级的真题、答案和考点总结,适用于考前刷题、考纲对照和教学备课。除历年认证真题外,还收录各等级认证提纲、客观题知识点总结(当前更新至五级,后续计划补充六级),并附带Python爬虫教程,帮助学习者拓展实用技能。资料已更新至2024年9月,并保持持续更新。压缩包整体约339MB,页面暂未标注具体文件总数与类型明细,内容以各级别真题、提纲、知识点文档为主,便于按等级与模块定位所需内容。目前已有866人学习/下载,适合需要系统梳理GESP考点、按等级逐级训练并查漏补缺的备考者。

1. 为什么刷了近千道GESP真题还是过不了:考纲比题量更值钱

很多人备考CCF编程能力等级认证(GESP)时有个误区,以为题刷得够多就能稳过。但真实情况是,GESP的题目重复率极高,尤其是1到4级,选择题和判断题反复考的就是那三四十个知识点:数据类型范围、短路运算、循环边界、字符串函数、排序稳定性。刷近千道题不如先把考纲拆明白,知道每道题在考哪个考点,才能把真题的价值榨干。这份资料的价值就在于把散落在各年真题里的重复考点抽成了提纲,配合真题答案直接标记高频考点位置。

GESP一共八个级别,一二三级考C++基础语法和简单算法,四到六级开始上数据结构,七八级基本就是信息学奥赛的入门难度。大多数准备CSP-J的同学会把GESP当成练手,因为两个考试的考点重叠度很高。后面几章我会把真题里反复出现的模块拆开讲,每一章都给考点清单、真题思路和容易翻车的地方。

2. 基础语法考点:等级一二三必考的四个模块与选择题真题思路

2.1 必考模块一:数据类型、运算符与类型转换

GESP低级别几乎每套卷子至少有四到六道题在考类型。最常见的考法是给一段代码问输出结果,考点落在整数除法、取模、类型提升和溢出这几个位置。

整数除法是最容易错的:两个int相除结果直接截断,比如7/2结果是3而不是3.5。如果要保留小数必须写成7.0/2或者把其中一个操作数转成double。取模运算对负数要留意,C++里-7%3的结果是-1而不是2,符号跟随被除数。类型转换的考点集中在int与double混算时int自动提升为double,以及char与int混用时字符的ASCII码参与运算。

提示:GESP选择题经常在同一道题里同时埋“截断”和“类型提升”两个陷阱,先判断操作数类型再算结果,顺序不要反。

真题里有这么一道常见考法:给代码int a=5; double b=2.5; cout<<a*b;问输出是什么类型。考的就是int乘double结果变成double。答题思路是先把表达式里最大的类型找出来,所有操作数往那个类型转,然后再计算结果。这类题不用动笔算,先看类型再算值,熟练之后三秒出答案。

2.2 必考模块二:短路运算、自增自减与优先级

这一块是判断题和选择题的常客。短路运算是GESP高频里最高频的一个:a && b中如果a为false,b根本不会执行;a || b中a为true,b也不会执行。真题常用的考法是让b的位置放一个自增表达式,比如a>0 || ++c>0,然后问c的值。解题的关键是先判断左侧能不能决定整个表达式的值,能决定就不看右边。

自增自减最常考的是前缀后缀的返回值区别:i++返回旧值,++i返回新值。单独的i++;和++i;效果相同,但在表达式里就会有差别。再看优先级:!高于算术运算符,算术高于关系,关系高于逻辑与和逻辑或。常见的易错题是int a=3,b=4; !a>b这种写法,实际运算顺序是(!a)>b,因为!优先级最高。

这类题的答题模板是先画括号,把优先级关系标出来,再从最内层括号开始求值。把优先级表记熟之后,这类题是纯送分题,但每年都有人错在把!a>b理解成!(a>b)。

2.3 必考模块三:三种控制结构与多重循环的输出题

循环和分支在GESP里不只是编程题的考点,选择题也大量出现。选择题喜欢考的是“这段代码循环执行几次”和“输出结果是什么”两类。循环次数的考点集中在for循环的初始化、条件判断和增量三步执行的时机,很多考生错在条件判断是“先判断后执行”还是“先执行后判断”,for循环是先判断再执行,条件不满足直接跳过。

多重循环嵌套考的是循环变量的变化轨迹。比如两层for循环,内层循环的边界依赖外层变量,这种题的常见解法是列出i等于前几个值时内层各执行几次,找到规律后直接数次数。不要试图在脑子里跑完整个循环,手写几行找规律更快。

分支结构的考点集中在else的匹配规则:else总是和最近的未匹配if配对。这个在缩进不规范时最容易出错。GESP真题有专门考这个的,给一段缩进混乱的代码问执行哪条分支,答案就看else的配对关系,不看缩进。

2.4 基础编程题模板:输入输出与循环的固定写法

编程题是GESP的大头,1到3级的编程题基本不需要算法,就是考察能不能用循环和分支写出正确的程序。最高频的题目类型是:给定n个数,求最大值、最小值、总和、平均值、统计符合条件的个数。这类题有一整套固定写法,这里给一个标准模板:

#include <iostream> using namespace std; int main() { int n; cin >> n; int maxVal = -1000000000; // 初始化为极小值 for (int i = 0; i < n; i++) { int x; cin >> x; if (x > maxVal) maxVal = x; // 打擂台求最大值 } cout << maxVal << endl; return 0; }

这段代码的关键点有两个:变量初始化必须是极小值,否则如果所有输入都比初值小,答案就是错的;求最大值用打擂台思路,每读一个数和当前最大值比较,比它大就更新。考生最容易错的是把maxVal初始化为0,如果输入全是负数输出就会错成0。这类模板题在2级和3级的编程题里反复出现,背熟这个结构能应付大量题目。

3. 算法考点:枚举、模拟、贪心与递归的真题解法套路

3.1 枚举法:GESP考得最多的算法,思路就是暴力

枚举法是GESP 2到4级的绝对主力。无论是水仙花数、完全数、质数判断,还是找满足条件的组合,本质都是把候选答案一个一个试。枚举法的难点不在于写出循环,在于确定枚举范围和枚举对象。

真题里有一道经典题:求100到999之间的水仙花数。水仙花数的定义是各位数字的立方和等于这个数本身,比如153 = 1³+5³+3³。这类题的枚举范围已经给了,剩下的就是把三位数拆成百位、十位、个位:

for (int i = 100; i <= 999; i++) { int a = i / 100; // 百位 int b = i / 10 % 10; // 十位 int c = i % 10; // 个位 if (a*a*a + b*b*b + c*c*c == i) { cout << i << endl; } }

代码里a、b、c三个变量的求法是最值得记的:百位是整除100,十位是先整除10再取模10,个位是直接取模10。拆位操作在GESP编程题里出现频率极高,而且后续学数组、学字符串都会用同样的思路。这类题的答题套路是“先拆位,再判断”,不要想着用数学公式直接算出答案,枚举就是最稳妥的方案。

3.2 模拟法:按题目描述一步步走

模拟类题目的特征是题目会描述一个过程,比如报数、约瑟夫环、简易计算器,你要把这个过程用代码原样翻译出来。这类题不考智商考细心,最容易失分的地方是边界条件。

一个典型例子是“报数游戏”:n个人围成一圈,从第1个人开始报数,报到3的人出局,问最后剩下的是原来的第几号。这题如果直接模拟,核心是维护一个“当前报数的人的位置”和“剩余人数”。循环的结束条件是剩余人数为1,每次报数遇到出局的人要跳过。答题思路是先把过程画出来,编号1到5的人手推一遍出局顺序,再想代码里怎么表示“跳过已出局的人”。

模拟题在3级、4级和5级都会出现,难度差异在于状态维护的复杂度。低级别用数组标记状态就够了,高级别可能涉及队列和链表。做题时先别急着写代码,在草稿纸上手动模拟一遍输入样例,确保自己理解了规则,再翻译成代码。

3.3 贪心算法:排序之后选最优

贪心在GESP 4级开始出现。最典型的题目是“活动安排”:给定n个活动的开始时间和结束时间,选尽量多的活动,使得活动之间不冲突。标准解法是“按结束时间从小到大排序,依次选结束早且不与前面已选活动冲突的”。

这个考点的答题思路要先证明“为什么按结束时间排序是对的”,简单理解是结束时间越早,留给后面的时间越多。这类题目考点拆开来就三个:结构体存开始结束时间、sort排序(自定义比较规则)、遍历选择。题目本身没什么变化,就是把场景换一下,比如换成“选课程”“安排会议”,底层解法完全一样。

考生容易在sort的自定义比较上翻车。GESP里结构体排序一般用sort(a, a+n, cmp),cmp函数返回true表示第一个参数排在前面。记法是一个口诀:返回true的时候,a排在b前面。写成return a.end < b.end;就是早结束的排前面。

3.4 递归考点:调用栈与终止条件

递归在GESP 2级就开始考基础题,4级以后会考到简单递归算法题。选择题常考“这个递归函数调用了几次”和“深度是多少”,编程题常考斐波那契数列和汉诺塔的移动步数。

递归的答题核心永远只有两句话:递推公式是什么,终止条件是什么。比如经典的阶乘递归:

int fact(int n) { if (n == 0) return 1; // 终止条件 return n * fact(n - 1); // 递推公式 }

这段代码的调用过程是fact(4)调用fact(3),fact(3)调用fact(2),一直压栈到fact(0)才返回。选择题考递归深度,实际上考的是函数压栈了几层。递归的易错点集中在终止条件不完整,比如求斐波那契数列如果只写n==0的终止条件漏掉n==1,就会无限递归甚至栈溢出。写递归的第一步永远是列终止条件,第二步才写递推关系,这个顺序不要反过来。

4. 数据结构考点:数组字符串结构体与排序的真题考法

4.1 数组:下标是逻辑不是顺序

数组在GESP里的考法比想象中灵活。最常见的是“计数数组”的用法:用一个数组统计每个数字出现的次数。题目场景比如“输入n个1到100之间的整数,统计每个数出现几次”。这类题不用排序也不用两重循环,开一个长度为101的数组,读到一个数x就执行cnt[x]++,输出时遍历cnt数组就行。

int cnt[101] = {0}; // 初始化为0,下标表示数字本身 for (int i = 0; i < n; i++) { int x; cin >> x; cnt[x]++; // 数字x出现次数加一 } for (int i = 1; i <= 100; i++) { if (cnt[i] > 0) cout << i << " " << cnt[i] << endl; }

这个模板的价值在于把时间复杂度从两重循环的O(n²)降到了O(n),GESP编程题如果n的数据范围在10万以上,两重循环就会超时,而计数数组是线性复杂度。数组题易错点有两个:一是数组下标越界,开了101的数组访问下标100没问题,但访问101就越界了;二是数组初始化,int cnt[101] = {0}意思是全部初始化为0,不写这个初始化直接声明,数组里的值是随机的。很多考生第一次提交就错在这个地方。

4.2 字符串:函数调用与字符遍历

GESP的字符串题从2级开始出现,考法集中在几个字符串函数和字符判断。常用函数有strlen求长度、strcmp比较大小、strcat拼接。但GESP更偏爱的考法是让考生自己遍历字符串处理每个字符。

真题里有一道高频题:输入一个小写字母组成的字符串,统计其中每个字母出现次数,并按字母序输出出现过的字母和次数。这题实际上就是计数数组,只是把数字换成了字符。做法是把字符c转换成下标c - 'a',遍历的时候逐个处理。这类题答题套路是三步:遍历字符串、用字符当下标统计、按下标顺序输出结果。

选择题里字符和整数的关系也是高频考点:'a'的ASCII码是97,'A'是65,数字字符'0'是48。看到代码里出现char + int的运算时,记住结果还是整数,只有赋值给char时才转回字符。易错题比如char c = 'a' + 1;结果是'b'还是98,要分清楚c里面存的是什么。

4.3 结构体与排序:固定套路拿分

结构体在GESP 4级开始考,最常见的题型是按某种规则排序。比如学生信息按成绩从高到低排,成绩相同按学号从小到大排。解法就是定义结构体加sort自定义规则。

答题模板很固定:

struct Student { int id; int score; }; bool cmp(Student a, Student b) { if (a.score != b.score) return a.score > b.score; // 成绩高的在前 return a.id < b.id; // 成绩相同学号小的在前 } sort(stu, stu + n, cmp);

这段代码的考点有三个:结构体成员访问用点号、cmp函数的返回逻辑、sort的排序区间是左闭右开[0, n)。常见错误是把sort(stu, stu + n, cmp)的第二个参数写成stu + n + 1,导致把数组最后一个元素后面的内存也排进去了。还有考生把cmp函数里大于号小于号写反,导致成绩从低到高排了。

注意:GESP判分是机判,排序顺序反了直接零分。写完cmp先自测一个两元素的小样例再交。

4.4 栈、队列的认知题:不考实现考理解

GESP 5级以前的栈队列基本只考认知层面的选择题,比如进出栈序列、队列先进先出的特点,很少要求手写栈和队列实现。

最常考的是“给定入栈顺序,判断哪个出栈顺序是合法的”。解题方法是用一个辅助栈模拟:依次让元素入栈,每入一个元素就检查栈顶是否等于出栈序列当前元素,等于就弹出。如果所有元素都处理完栈还没弹空,说明序列不合法。这类题在草稿纸上画两遍就会,硬背结果反而记不住。

队列考的更简单,基本是判断“先进先出”特性。场景题比如“排队买票,第一个人买完离开,新的人从队尾加入”,问此刻队首是谁。答题思路是记住队首永远是下一个要处理的元素。这类考点虽然简单但要拿满分,因为GESP的选择题正确率直接影响等级评定。

5. 失分点:五个最容易丢分的地方,错在哪和怎么改

5.1 数组越界的边界判断

考生最容易在循环边界上翻车。比如定义int a[100],循环写for(int i=0; i<=100; i++),最后一次访问a[100]越界。这类错误在GESP机判时往往不是当场报错,而是悄悄覆盖了相邻内存,导致输出结果诡异。为什么错:C++不对数组越界做检查,越界读写可能不崩溃,但结果不可预测。怎么改:写循环时养成习惯,看到i<=n都要停下来想一下数组长度到底是多少,凡是数组长度为n,循环边界就只到n-1。

5.2 int溢出导致答案错

GESP题目经常给到10^9级别的数据范围。两个int相乘可能溢出成负数,导致计算结果完全错误。为什么错:很多考生只记住int范围是约21亿,但没算乘法会不会超。怎么改:看到数据范围超过10^9,把变量声明成long long;乘法表达式里有一个long long,结果就会自动提升为long long。

5.3 字符串比较用错方法

用==比较两个字符串变量在C++的string类里是合法的,但如果用的是char数组,==比较的是数组首地址而不是内容,永远不等。真题里常出现的陷阱是让char数组用==和另一个char数组比较,代码编译不报错但结果永远是false。怎么改:先看题目里字符串是string类型还是char数组,string直接用==,char数组用strcmp(a, b)==0判断相等。

5.4 cin读入字符串遇空格截断

cin >> str遇到空格就停止读取,如果题目输入是一整行带空格的句子,必须用getline(cin, str)。为什么错:GESP有些输入数据一行里有多个单词,用cin只能读进第一个。怎么改:看到“一行字符串”四个字优先用getline;用了getline之后注意前面有没有cin残留的换行符,有的话先执行一次cin.ignore()。

5.5 变量未初始化

声明一个局部变量不赋值就直接用,初值是一块随机内存中的内容。为什么错:本地调试时运气好变量初值是0,测试数据一换就翻车,机房评测和本地结果不一样。怎么改:声明变量后立刻给初值,计数数组用={0}初始化,求最大值初值设极小值,求最小值初值设极大值。这个习惯改掉之后,程序题的稳定性会明显提升。

6. 考场实操策略:三遍刷题法与时间分配模板

这里分享一个亲测有效的备考模式和考场时间分配思路。备考阶段用“三遍刷题法”:第一遍按考点模块刷,每章知识点学完立刻做对应真题,题目数量不用多,每类考点做八到十道即可;第二遍按整套卷子做,卡时间模拟真实考试,重点看哪些考点反复错;第三遍只重做错题,把错因按上面五类失分点归类,重新写完整代码而不是看一眼答案。三次筛选之后,薄弱点就非常具体了,不会出现“感觉哪都差点”的情况。

考场时间分配建议:选择题大约15到20题控制在20分钟内,判断题控制在10分钟内,剩下所有时间都给编程题。编程题的做题顺序是“先读题再动笔”,先花两分钟读清楚输入输出格式和样例,再确定算法,最后才写代码。写完代码必须手动跑一遍样例输入,看看输出是否一致,这一步能救回不少粗心错。

一个实用的调试习惯是“分步打印”:在处理循环时打印当前变量值,处理完之后再删掉打印语句。第一次做某道模拟题时,手算样例跑出一个中间结果,代码跑出另一个,打印插在中间发现是边界条件处理错了。从那以后我每次做GESP编程题都强制走一遍“读题确认边界、手推样例、代码实现、打印验证”的流程,虽然多花几分钟,但整份卷子的容错率高了很多。这套方法同样适用于CSP备考,希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进