
简介面向CCF编程能力等级认证GESP1至8级考生的真题与考点资料包覆盖Scratch图形化、Python、C三条备考路径适合需要按级别梳理考纲、练习历年试题并查漏补缺的中小学生、信息学奥赛入门者及指导教师。内容包含1至8级真题与答案、各等级认证提纲以及客观题知识点整理真题已更新至2024年9月并持续补充客观题知识点目前更新至五级、第六级在筹备中另附Python爬虫教程便于在等级考试之外延伸项目实践。资源以zip压缩包交付约339MB文件总数与主要文件类型明细在页面暂无数据具体目录需以解压后的实际内容为准。已有867人学习或下载可用于分级备考、考前自测、题型归纳与知识点复盘帮助读者按Scratch、Python、C不同语言路线建立清晰的复习顺序。1. 编程能力等级认证先弄懂评分逻辑再谈刷题量编程能力等级认证的真题翻车点常常不在算法而在读题。带过几轮考级班的同学会发现一个反直觉现象越是盯着“会不会写循环”练越容易在输入格式、数据范围和输出换行上丢分。这门认证按级别递进低级别考语法与流程控制高级别才逐步引入数组、字符串、函数和简单算法每一级都有明确的能力边界。想稳过先把每一级的考点分布摸清再用真题验证自己是不是真的会写而不是只会看懂。下面按“考什么、怎么答、哪里错”的顺序拆适合正在备考等级认证、准备信息学竞赛入门的孩子和陪练的家长。2. 考点分布分级考纲里真正拉开分差的四类题等级认证的考纲条目看起来多真正拉开分差的就是四类输入输出与流程控制、数组与字符串、函数与递推、简单算法与复杂度。低级别丢分集中在格式和边界高级别丢分集中在效率和下标。复习时间有限时先把前两类的正确率压到接近满分再攻后两类性价比最高。下面这张表不是官方分值而是按公开样卷和历年考生反馈整理的复习权重用来决定时间怎么分。级别段核心考点建议复习占比常见题型入门级输入输出、顺序、分支、循环40%求和、判断、图形打印进阶级一维/二维数组、字符串、函数35%统计、矩阵、回文提高级排序、查找、递推、简单算法25%排序输出、二分、模拟2.1 低级别输入输出、分支与循环是送分区低级别的题本质是把自然语言翻译成几行代码。读两个数输出和、判断奇偶、累加求和、找最大值、按行打印星号这些题型占了大头。它们不难但送分区恰恰是失分重灾区原因集中在三处输入格式没看清、循环边界多一少一、输出少了换行。练习时不要贪多每天五道基础题限时完成做完必须自己造三组数据验证最小规模、最大规模、中间值。比如求和题n1 时程序会不会输出 0n 取到题目上限时变量会不会溢出这些都要亲手试。低级别把这三件事做成习惯后面高级别才不会反复栽在同一个坑里。循环边界可以记一个笨办法把循环变量在纸上写出来。for (int i 0; i n; i)跑一遍 n3纸上写 0、1、2确认正好三个数换成i n就变成四个一眼能看出来。这个动作花不了十秒比考完再后悔划算。2.2 中级别数组与字符串决定能不能过线到了中级别题目开始要求“存下来再处理”。一维数组用来存一组数做统计、找最大最小、去重二维数组处理矩阵转置、杨辉三角字符串处理回文、字母统计、子串替换。这一段的分水岭是下标意识数组下标从 0 开始长度是元素个数最后一个元素的下标是长度减一。字符串题有两个高频失分点。第一把字符和数字混在一起0和0不是一回事第二大小写没统一统计字母时只算了小写大写全漏。练的时候刻意把这两类数据都造一遍全大写、全小写、大小写混合、带空格。带空格的字符串要用整行读入普通的cin s遇到空格就停读进来只有半个句子。数组和字符串的常用操作可以对照着记操作数组写法字符串写法注意点取长度额外变量 ns.size()size 返回无符号数比较时转 int访问元素a[i]s[i]下标从 0 开始遍历计数循环范围 for 或下标范围 for 改值要加引用判空n 0s.empty()空串长度是 0不是 12.3 高级别函数、递推与排序是拉分项高级别的题开始考“组织代码”的能力。函数用来封装重复逻辑比如判断素数、求最大公约数、交换两个数递推用来解决爬楼梯、斐波那契、路径计数这类有状态转移的题排序和二分用来处理“按顺序输出”“查找第一个满足条件的位置”。这一段最容易被忽视的是复杂度意识。n 只有 1000 时双重循环完全跑得动n 到了 100000双重循环就是十的十次方评测机直接超时。拿到题先看数据范围再决定用哪种写法这个顺序不能反。排序题也一样数据量小可以手写冒泡数据量大就要用标准库的排序函数同时要会手写一遍防止题目限制。递推题的得分点在于把“第 i 项怎么由前面几项推出来”写清楚。爬楼梯是f[i] f[i-1] f[i-2]路径计数是dp[i][j] dp[i-1][j] dp[i][j-1]写代码之前先在纸上列前三项验证递推式对不对再落到循环里。这个习惯能挡掉一大半“样例过了但隐藏数据全错”的情况。2.4 真题演练三道分级样题的答题思路第一道是低级别的多组数据求和并输出最大值。题干通常写“读入若干组数据每组先给个数 n再给 n 个整数输出和与最大值”。很多同学只处理一组或者最大值初值设成 0遇到全负数就错。#include iostream using namespace std; int main() { int n; // while (cin n) 表示一直读到没有数据为止适配多组输入 while (cin n) { int sum 0; int mx -1000000000; // 初值要足够小防止全负数时出错 for (int i 0; i n; i) { int x; cin x; sum x; if (x mx) mx x; // 边读边更新省掉一个数组 } cout sum mx endl; } return 0; }这段代码的关键在while (cin n)它把“还有没有下一组”交给输入流判断不用提前知道组数。mx的初值取负的十亿是因为题目数据范围通常在 int 内取 0 会让全负数数据直接翻车。循环里没有开数组边读边算内存占用恒定n 很大也不会爆。第二道是中级别的字母统计。题干给一行字符串要求按字母顺序输出每个出现过的字母和次数大小写算同一个字母。思路是开一个 26 格的计数数组把每个字符映射到 0 到 25 的下标。#include iostream #include string using namespace std; int main() { string s; getline(cin, s); // 整行读入保留空格 int cnt[26] {0}; for (char c : s) { if (c a c z) cnt[c - a]; else if (c A c Z) cnt[c - A]; // 大写统一折到小写 } for (int i 0; i 26; i) { if (cnt[i] 0) cout char(a i) cnt[i] endl; } return 0; }c - a用的是字符的编码差值把 a 到 z 压进 0 到 25。大写分支减的是A但存的位置和小写一致所以统计结果合并。输出循环从 0 到 25天然按字母序不需要额外排序。这里用getline而不是cin s就是为了不让空格截断输入。第三道是提高级的冒泡排序。题干要求读入 n 个数从小到大输出n 不超过 1000。虽然标准库有排序函数但考级常要求手写评分点在看是否理解两层循环的范围。#include iostream using namespace std; int main() { int n, a[1005]; cin n; for (int i 0; i n; i) cin a[i]; for (int i 0; i n - 1; i) { bool swapped false; // 记录本轮有没有交换 for (int j 0; j n - 1 - i; j) { if (a[j] a[j 1]) { swap(a[j], a[j 1]); swapped true; } } if (!swapped) break; // 已经有序提前收工 } for (int i 0; i n; i) cout a[i] ; return 0; }外层跑 n-1 轮每轮把当前最大的数送到末尾所以内层比较范围是n - 1 - i已经排好的尾巴不再碰。swapped是优化某一轮一次交换都没有说明整个数组有序直接跳出。数组开 1005 是留余量题目说 n 不超过 1000多开几个防止下标写错时越界。3. 高频考点字符串、排序、模拟题的固定套路翻历年真题字符串、排序、模拟这三类出现的频率最高。它们的共同点是题干长、细节多、套路固定。把这三种套路练熟考场上大部分题都能往模板上靠。这一章按题型拆每类给一个可复用的骨架再用真题验证。3.1 字符串回文、统计、替换三类模板回文题的判断骨架是双指针一个从前往后一个从后往前字符不同就判否相遇就判是。这个骨架能直接搬到“判断回文数”“最长回文子串”的简化版。统计题的骨架是计数数组或哈希表把字符映射成下标。替换题的骨架是遍历原串遇到目标字符就拼接新内容或者直接改原串。回文判断的代码短但边界多。空串算不算回文单字符算不算大小写要不要敏感题目都会明确写。读题时把这几个条件圈出来代码里对应加分支。下面是最基础的双指针版本bool isPalindrome(const string s) { int l 0, r (int)s.size() - 1; // size 是无符号数转 int 再减 while (l r) { if (s[l] ! s[r]) return false; l; --r; } return true; }l r而不是l r是因为中间那个字符不需要和自己比。(int)s.size() - 1先转有符号再减避免空串时无符号数下溢成巨大值。函数参数用 const 引用避免拷贝这是字符串题的好习惯。统计题的高频变形是“只统计字母”“忽略大小写”“按出现次数排序”。前两个在上一章的代码里已经处理第三个需要在计数后把有值的字母拎出来排序。排序规则通常是次数降序、字母升序写比较函数时两个条件都要写全只写一个会在次数相同时顺序错乱。替换题常考的是“把连续多个空格压成一个”。这类题不要用replace反复改串边遍历边拼新串更稳。遇到空格就标记下一个非空格字符到来时补一个空格其余字符直接追加。这个写法一遍过不会出现替换后下标错位的问题。3.2 排序与查找手写排序与二分的得分点排序题的得分点不在“能排出来”而在“排得对、排得稳”。冒泡、选择、插入三种手写排序要会至少两种知道它们的循环范围怎么定。选择排序是每轮找最小值换到前面插入排序是把当前元素插到已排好部分的正确位置冒泡是相邻比较。三种写法都要能默出来考试时根据题目限制选。二分查找的高频考法是“在有序数组里找第一个大于等于目标的位置”也就是常说的下界。手写时区间定义要统一推荐左闭右开循环条件是l r更新时l mid 1或r mid最后返回l。int lowerBound(const int a[], int n, int target) { int l 0, r n; // 左闭右开r 取 n 表示可以插入到末尾 while (l r) { int mid l (r - l) / 2; // 防止 l r 溢出 if (a[mid] target) l mid 1; else r mid; } return l; // 第一个 target 的下标找不到时等于 n }mid写成l (r - l) / 2而不是(l r) / 2是为了在 l 和 r 都很大时不溢出。返回值l有两个含义找到了就是目标位置没找到就是它应该插入的位置。这个性质在“统计小于某数的个数”这类题里直接能用。排序和查找组合起来的高频题是“先去重排序再二分查找”。去重可以在排序后用双指针完成也可以直接用集合。考级环境里集合的常数比较大数据量上万时手写去重更稳。去重后的数组长度变了后续二分的右边界要跟着改这是常见的失分点。3.3 模拟题把长题干翻译成状态表模拟题是题干最长、最容易读懵的一类。它不考复杂算法考的是把一段规则翻译成代码的能力。常见场景有排队叫号、计分排名、日期推算、电梯运行。这类题的破法是先画状态表有哪几个变量每个变量在每一步怎么变变化的顺序是什么。以“统计每个人答对题数并排名”为例状态表至少有三列人、答对题数、是否已输出。规则里通常藏着“答对题数相同按编号升序”这种细节读题时用笔圈出来。变量定好再写循环循环里按“读入一条记录、更新对应人的计数、标记状态”的顺序走不要一边读一边输出否则排序会乱。日期题是模拟里的常客。核心是每个月的天数表和闰年判断。闰年规则写成一个函数二月天数跟着变。跨年、跨月、月末加一天这些边界造数据时逐个试。很多同学样例过不了不是逻辑错是月份数组下标从 0 开始还是从 1 开始没统一。模拟题的时间分配要克制。题干读完先花一分钟写状态表再花十分钟写代码最后留五分钟造边界数据。上来就敲代码写到一半发现变量少了一个返工的时间够做两道基础题。3.4 真题演练两道高频题的完整答法第一道是字符串统计的变形给一行文本输出出现次数最多的字母及其次数次数相同输出字母序最小的。思路是计数数组加一次遍历比较。#include iostream #include string using namespace std; int main() { string s; getline(cin, s); int cnt[26] {0}; for (char c : s) { if (c a c z) cnt[c - a]; else if (c A c Z) cnt[c - A]; } int best 0; for (int i 1; i 26; i) { // 只有严格大于才替换保证次数相同时留下字母序更小的 if (cnt[i] cnt[best]) best i; } if (cnt[best] 0) cout No letters endl; else cout char(a best) cnt[best] endl; return 0; }比较循环从 1 开始best初始为 0只有cnt[i]严格大于当前最优才更新这样次数相同的字母不会被后面的覆盖天然满足“字母序最小”。全无字母时输出提示这个分支题干一般会写读题时别漏。第二道是模拟题n 个人排队每次报到 m 的人出队输出出队顺序。这是约瑟夫环的简化版。用数组标记每个人是否还在队里循环数数数到 m 就输出并标记出队直到所有人出完。#include iostream using namespace std; int main() { int n, m; cin n m; bool out[1005] {false}; // false 表示还在队里 int left n; // 剩余人数 int pos 0; // 当前报数位置 while (left 0) { int step 0; while (step m) { if (!out[pos]) step; // 只有还在队里的人才报数 if (step m) break; pos (pos 1) % n; // 环形后移 } cout pos 1 ; // 题目按 1 开始编号 out[pos] true; --left; pos (pos 1) % n; // 从下一个人继续 } return 0; }外层控制剩余人数内层数到 m。pos用取模实现环形移动out数组标记出队的人数数时跳过。输出pos 1是因为题目从 1 编号而数组从 0 开始。这段代码的易错点在“数到 m 之后从下一个人重新开始”pos在出队后要再后移一次漏了这一步会重复数到同一个人。4. 真题精练从读题到AC的完整链路同一道题有人二十分钟写完还检查了两遍有人四十分钟还在改下标。差距不在打字速度在流程。这一章把一道题的完整处理链路拆成四步读题、实现、自测、分配时间。每一步都有固定动作照着走能把低级失误压到最低。4.1 读题圈出输入输出、数据范围与关键词读题的第一遍只做三件事圈输入格式、圈输出格式、圈数据范围。输入是单组还是多组每个数是什么类型输出要不要换行、要不要空格分隔这些决定代码骨架。数据范围决定变量类型和算法复杂度n 到十万就不能写双重循环。第二遍读题圈关键词。“至少”“恰好”“不超过”“连续”“不同”这几个词每个都对应一个分支。把“至少”看成“恰好”答案直接错一半。题面上如果有样例把样例在纸上手动跑一遍确认自己理解的规则和样例输出一致再动手写。读题时还要注意隐藏条件。比如“字符串只包含小写字母”和“字符串可能包含空格”是两种完全不同的读入方式前者用cin后者必须getline。题目没明说但样例里有空格按有空格处理。这个判断做错后面代码写得再漂亮也是零分。提示读题时间不要省一道题读三分钟比写完发现理解错再返工省十分钟。4.2 代码实现以一道统计题为例看一道综合题给 n 个学生的成绩输出平均分保留两位小数、最高分、以及高于平均分的人数。这道题把输入、数组、统计、格式化输出串在一起是中级别的典型题。#include iostream #include iomanip using namespace std; int main() { int n; cin n; int a[1005]; int sum 0, mx -1; for (int i 0; i n; i) { cin a[i]; sum a[i]; if (a[i] mx) mx a[i]; } double avg (double)sum / n; // 先转 double 再除避免整数除法 int cnt 0; for (int i 0; i n; i) { if (a[i] avg) cnt; // 与平均分比较注意 avg 是浮点数 } cout fixed setprecision(2) avg endl; cout mx endl; cout cnt endl; return 0; }(double)sum / n是关键sum和n都是整数直接除会截断小数。输出用fixed加setprecision(2)固定两位小数这两个要一起用只写setprecision可能输出成科学计数法。统计高于平均分的人数时a[i]是整数、avg是浮点数比较会自动提升类型不需要手动转。变量命名尽量见名知意sum、mx、cnt、avg比a1、b2好排查。数组开 1005 是习惯性留余量题目上限 1000。这些细节单独看都小凑在一起就是“样例全过、隐藏数据挂掉”的根源。4.3 自测与对拍自己造数据的三个方向代码写完样例过了不代表对。自己造数据至少覆盖三个方向边界、特殊、随机。边界是最小规模和最大规模n1、n 取上限、所有数相同、所有数不同。特殊是题目里提到的极端情况全负数、空串、只有空格、刚好等于平均分。随机是用脚本生成一批数据和暴力解法对拍。对拍的思路很简单写一份肯定正确但很慢的暴力代码再写一份要提交的代码用同一组输入跑比较输出。随机数据可以用几行脚本生成跑一百组有一组不同就停下来看那组数据。# 生成 100 组随机数据并对拍gen 生成数据slow 是暴力解fast 是提交解 for i in $(seq 1 100); do python3 gen.py in.txt # 生成一组输入 ./slow in.txt out1.txt # 暴力解输出 ./fast in.txt out2.txt # 提交解输出 if ! diff -q out1.txt out2.txt /dev/null; then echo 第 $i 组不一致 break fi doneseq 1 100控制组数diff -q只判断是否相同不打印差异break让第一组不一致就停下方便定位。对拍不要求每次都做但排序、二分、递推这三类题建议养成习惯它们的错误往往藏在小数据里看不出来。4.4 答题纸与时间分配先拿稳的分上机考试的时间分配按“先易后难”排。开考先花五分钟通读所有题按把握程度标一二三档一档题先做做完立刻检查输入输出格式。二档题留足时间三档题放最后做不出来就把能拿的部分分写上比如输出样例、写个暴力版本。检查清单固定三条输入方式对不对、输出格式对不对、数组够不够大。这三条能挡住大部分非逻辑失分。变量命名在考试里不用追求短maxScore比mx多敲几个字符排查时省的时间更多。代码写完不要急着交用题目样例再跑一遍手算一组边界数据再跑一遍两遍都过再进入下一题。5. 易错点五类最常见的失分题带练过程中反复出现的错误就那几类每类都有固定的错法和固定的改法。这一章按“错在哪、为什么错、怎么答对”拆五条都是考场上真实丢过分的地方。5.1 输入输出类格式、换行、多组数据第一条多组数据只处理了一组。题干写“输入包含多组数据读到文件末尾”代码里只写了一次cin n后面的数据全没读。错在没识别多组输入的标志这类题必须用while (cin n)或while (scanf(...) ! EOF)包住整个处理逻辑。答对的办法是读题时看到“多组”“若干组”“直到输入结束”就条件反射写循环读入。第二条输出少了换行或多了空格。题目要求每个结果占一行代码里用空格分隔或者要求空格分隔代码里每个数后面都跟一个空格行末多出空格。多数评测机对行末空格宽容但对换行严格。答对的办法是照着样例输出逐字符对样例里是endl还是空格代码里就一模一样。5.2 边界与下标类0、1、最大值、空串第三条最大值初值设成 0。题目数据全是负数最大值应该是 -3代码输出 0。错在初值没有覆盖数据范围mx 0只适合非负数据。答对的办法是初值取题目数据范围的下界再往下一点比如-1e9或者先读第一个数当初始最大值。第四条循环多跑一次或少跑一次。for (int i 0; i n; i)访问了a[n]越界或者i n - 1漏了最后一个元素。错在边界没在纸上验。答对的办法是写完循环立刻用 n3 在纸上跑一遍写下 i 的每个取值确认首尾都对。5.3 类型与读题类精度、溢出、“至少”与“恰好”第五条整数除法丢了小数或者大数相乘溢出。求平均分写成sum / n两个 int 相除直接截断或者两个十万相乘int 装不下变成负数。错在对类型和范围不敏感。答对的办法是除法前先转double乘法前估算最大乘积超过 int 范围就换long long。读题时把“至少”“恰好”“不超过”圈出来每个词对应一个判断条件写完逐条对照别凭印象。6. 答题技巧上机前十分钟的检查清单考场上真正拉开差距的往往不是谁会更难的算法而是谁少犯低级错误。我自己的习惯是开考前十分钟不碰代码先把下面这张表在脑子里过一遍再开始读题。检查项具体动作对应失分输入方式单组还是多组有没有空格多组只读一组、字符串被截断数据范围n 多大要不要 long long溢出、超时输出格式换行、空格、小数位格式错、精度错边界n1、全负数、空串越界、初值错时间分配先易后难留十分钟检查会做的没做完这张表不用背做三套真题就能形成条件反射。真正要练的是“写完不等于做完”每道题写完先用样例跑再手造一组边界数据跑两遍都过才进入下一题。排序题重点看循环范围字符串题重点看读入方式统计题重点看初值和类型转换。有一次带练一个同学五道题样例全过最后只拿了一半分。复盘发现三道题栽在输出格式一道题最大值初值写成 0还有一道多组数据只处理了第一组。这些错没有一个是“不会”全是流程漏了。从那以后我每次让他交卷前强制走一遍检查清单同样的分再没丢过。你也可以把这张表打印出来贴在桌前练到不用看就能想起来为止。希望帮到你。本文还有配套的精品资源点击获取