☰
CSP-J 2024初赛真题解析:选择题高频考点与阅读完善程序答题逻辑
2026/10/31 7:27:04 网站建设 项目流程

简介:面向备战信息学奥赛CSP-J入门组初赛的学生、少儿编程教师及辅导家长,这份二〇二四年真题详细分析以C++考点为主线,将单项选择题按基础知识、算法与数据结构、数学逻辑、编程语言知识和操作系统常识分类讲评。内容结合原题给出答案与解析,重点拆解三十二位整型存储范围、格雷码特性、二进制与十六进制换算、二分查找比较次数、栈的出栈序列、二叉树前中后序遍历、无向图度数、组合计数及相邻排列等问题,帮助读者按薄弱环节查漏补缺。压缩包共一个docx文档,约一百二十一KB,篇幅紧凑,适合打印批注、课堂讲义或错题整理。当前已有两千五百九十四人学习,可作为初赛冲刺阶段自测、复盘与教师备课的参考材料。

1. CSP-J 2024 初赛真题到底考什么:从一道 int 范围题看 30 分选择题的拿分逻辑

CSP-J 2024 初赛真题第一题就把很多人的“背概念”思路打回原形:32 位 int 的存储范围,四个选项只差一个端点,考的不是死记,而是补码范围 -2^31 到 2^31-1 的边界。入门组初赛满分 100 分,单项选择题 15 题共 30 分,阅读程序 40 分,完善程序 30 分。选择题决定你能不能稳住基本盘,阅读程序和完善程序决定你能不能拉开差距。适合已经学过 C++ 基础语法、准备第一轮笔试的入门组考生,也适合从少儿编程转竞赛、需要快速摸清命题套路的人。拿分关键不是刷偏题,而是把高频考点做成条件反射:看到 int 想边界,看到组合想分类,看到递归先写递归基。

2. 选择题高频考点:位运算与进制、组合计数、数据结构性质的三类送分题

选择题 15 题、每题 2 分,考点分布很稳定。把 2024 年这套题拆开看,计算机基础、数学计数、数据结构性质几乎各占一块。很多考生丢分不是不会,而是把“会背”当成“会做”:int 范围记成对称区间,组合题漏掉分类,栈序列只看第一个出栈元素。下面按题型把容易反复出现的考点讲透。

题号考点答案拿分动作
132 位 int 范围C记住 -2147483648 到 2147483647
2进制混合计算A全部转十进制再算
3部门抽样组合B先确定哪个部门出 2 人
4格雷码序列D检查相邻项是否只变一位
5存储单位换算D1MB=1024×1024×8 bit
6C++ 基本类型Cstruct 是复合类型
7C++ 循环语句D没有 repeat-until
8字符偏移B'a'+13 得 'n'
9二分查找比较次数B1000 个元素最多 10 次
10操作系统识别A文本处理软件不是系统
11无向图度数和B度数和等于边数两倍
12二叉树遍历A前序定根,中序分左右
13栈的出栈序列D模拟栈顶,别跳元素
14相邻排列A捆绑后乘内部排列
15编译器作用B高级语言转机器代码

2.1 整型范围与存储单位:端点差一就是送分变送命

第 1 题四个选项的差别只在端点:A 和 B 少了负数端点或多了正数端点,D 两端都多 1。32 位有符号 int 用补码表示,范围是 -2^31 到 2^31-1,也就是 -2147483648 到 2147483647,选 C。这里最常见的错误是把正负范围写成对称的,看到 -2147483648 到 +2147483648 觉得很“整齐”就选了 D。补码的正数最大值比负数绝对值小 1,这个不对称是硬规则。

第 5 题考存储单位换算:1MB = 1024KB,1KB = 1024B,1B = 8bit,所以 1MB = 1024×1024×8 = 8388608 bit,选 D。题干里“1Kb 位 1024 字节”这类表述容易让人分心,真正要抓的是 B 与 bit 的 8 倍关系。考场上先写一条换算链:MB→KB→B→bit,每一步乘 1024 或 8,不要跳步。选择题里这种题一旦跳步,很容易把 1048576 当成最终答案。

提示:遇到 int 范围题,先写“4 字节、32 位、补码、正数少 1”;遇到存储换算题,先写“B 和 bit 差 8 倍”。

2.2 进制与格雷码:先转十进制,再排除相邻位变化

第 2 题看起来符号很多,核心动作是全部转十进制。题面里的 148 按八进制理解是 12,10102 按二进制是 10,D16 按十六进制是 13,11012 按二进制是 13,于是 (12-10)×13-13 = 2×13-13 = 13,选 A。这里不是考你心算多快,而是考你看到下标记号能不能立刻判断进制。平时练习要养成习惯:先把每个数旁边标“八进制/二进制/十六进制”,再统一转十进制,最后按普通四则运算做。

第 4 题考 4 位二进制格雷码。格雷码的硬特征是相邻两个编码只有一位不同。判断时不要试图背完整序列,直接看选项里相邻项异或结果是不是只有一个 1。比如序列从 0000 到 0001 只变最后一位,0001 到 0011 只变倒数第二位,继续检查到末尾。D 项 0000,0001,0011,0010,0110,0111,0101,0100 满足相邻只变一位,选 D。A、B、C 的破绽通常在中间某一步同时变了两位,或者末项与前面接不上。

格雷码题还有一种常见问法:给一个二进制数求对应格雷码,或者给格雷码反推二进制。答题模板是“最高位保留,后面每一位用相邻两位异或”。这类题不需要写代码,手算两三项就能验证规律。别在考场上从头推公式,先拿选项做排除,速度更快。

2.3 组合计数与相邻捆绑:分类清楚,乘加别混

第 3 题是 10 名员工分在 4、3、3 三个部门,选 4 人且每个部门至少 1 人。4 人分到 3 个部门,必然有一个部门出 2 人,另外两个部门各出 1 人。于是分三类:A 部门出 2 人,C(4,2)×C(3,1)×C(3,1)=6×3×3=54;B 部门出 2 人,C(4,1)×C(3,2)×C(3,1)=4×3×3=36;C 部门出 2 人,同样 36。三类相加 54+36+36=126,选 B。这里最容易错在只算一种分类,或者把三类乘起来。分类用加法原理,分步用乘法原理,题干里“哪个部门出 2 人”就是分类信号。

第 14 题是 5 个男生和 3 个女生站成一排,3 个女生必须相邻。相邻问题用捆绑法:把 3 个女生捆成 1 个整体,和 5 个男生一共 6 个对象排列,6! = 720;3 个女生内部还可以换顺序,3! = 6;总数 720×6 = 4320,选 A。血泪经验是只算 6! 就收手,忘了内部排列。凡是“必须相邻”“必须在一起”,先捆绑,再乘内部排列;凡是“不能相邻”,先排其他人,再插空。

提示:组合题写完算式后回读一遍题干,确认“至少”“恰好”“相邻”“不同部门”这些限制有没有全部用上。

2.4 二叉树遍历与栈序列:前序定根,中序分左右,栈要模拟栈顶

第 12 题给前序 [A,B,D,E,C,F,G] 和中序 [D,B,E,A,F,C,G],求后序。前序第一个 A 是根,中序里 A 左边 D,B,E 是左子树,右边 F,C,G 是右子树。左子树前序 B,D,E、中序 D,B,E,得到后序 D,E,B;右子树前序 C,F,G、中序 F,C,G,得到后序 F,G,C;整体后序 D,E,B,F,G,C,A,选 A。做这类题不要一上来画完整树,先写“根—左—右”的分割,再递归处理左右子树,最后按“左、右、根”拼后序。

第 13 题问哪个出栈顺序不可能,入栈顺序是 1 2 3 4 5 6。D 项 1 3 5 2 4 6 的问题出在 5 出栈之后:此时 1 已出,2、3、4 都曾入栈,栈顶是 4,下一个要出 2 就必须先把 4 出掉,矛盾。做栈序列题不要凭感觉,拿纸画一个栈,按目标序列模拟:目标元素如果还没入栈,就继续入栈;如果已经入栈但不在栈顶,就非法。二分查找第 9 题也是同理,1000 个元素最多比较次数是 ceil(log2 1000)=10,选 B,别把“最多”当成“平均”。

第 11 题无向图所有顶点度数之和等于边数的两倍,选 B。一条边贡献两个端点度数,这个性质在选择题里几乎年年换皮出现。第 10 题按“文本处理软件不是操作系统”记,选 A。第 15 题编译器的主要作用是把源代码转换为机器代码,选 B。第 6 题 struct 是复合数据类型,不是基本类型,选 C。第 7 题 C++ 没有 repeat-until,选 D。第 8 题 'a'+13 得 'n',选 B。这些题不需要深挖,考前把易混点过一遍即可。

3. 阅读程序题:从“算结果”到“改条件后会不会翻车”

阅读程序 40 分,是初赛的分水岭。2024 年这套题里,素数统计、动态规划、递归函数三块很典型。阅读程序不是让你从头到尾逐行翻译,而是先看问题问什么,再带着问题找关键行:循环边界、递归基、返回值、状态转移。判断题常考“改一个条件后结果变不变”,选择题常考“输入某个值时输出是多少”。答题顺序建议先做判断题,再做选择题,因为判断题往往能帮你确认程序功能。

3.1 素数统计程序:isPrime 的边界和 count/sum 的输出

先看这段素数统计代码的核心结构:

bool isPrime(int n) { if (n <= 1) return false; // 0、1 不是素数 for (int i = 2; i * i <= n; i++) { // 只试到 sqrt(n) if (n % i == 0) return false; // 找到因子,不是素数 } return true; } int countPrimes(int n) { int count = 0; for (int i = 2; i <= n; i++) { if (isPrime(i)) count++; // 统计 2 到 n 的素数个数 } return count; } int sumPrimes(int n) { int sum = 0; for (int i = 2; i <= n; i++) { if (isPrime(i)) sum += i; // 累加 2 到 n 的素数和 } return sum; }

这段代码的逻辑很直:isPrime用试除法判断素数,循环条件是i*i <= n;countPrimes统计个数,sumPrimes累加和。参数n是输入上界,i从 2 开始,因为 0 和 1 不是素数。第 16 题输入 10,10 以内素数是 2、3、5、7,个数 4,和 17,判断题正确。第 18 题说sumPrimes计算 2 到 n 的所有素数之和,正确。第 19 题输入 50,素数和是 328,选 B。

第 17 题把isPrime的条件改成i <= n/2,输入 20,问countPrimes(20)是否变为 6。答案是错误,仍然是 8。20 以内素数还是 2、3、5、7、11、13、17、19,共 8 个。改条件只影响效率,不影响素数判断的正确性,除非边界写错。第 20 题把i*i <= n改成i <= n,输入 10,问输出。注意isPrime(2)时循环从 i=2 开始,2<=2 成立,2%2==0,会把 2 误判为非素数;isPrime(3)时 3%3==0,也会误判。这样 10 以内素数个数和和都不对,选 A“将不能正确计算 10 以内素数个数及其和”。这类题最容易翻车的地方是把“改条件”当成“原程序”直接套答案。正确动作是拿 n=2、n=3、n=4 三个边界用例重新跑一遍。

3.2 动态规划阅读:dp[i-1] 和 dp[i-2] 的转移别改错

动态规划阅读题的关键是抓住状态转移式。题干里的核心形式是:

// 简化后的状态转移,按题面 cost 数组理解 dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1];

这段代码的含义是:到达第 i 个状态的最小花费,由前一个状态或前两个状态中的较小值,加上当前cost[i-1]得到。参数i是状态下标,cost是每一步的花费数组,dp是前缀最小花费。第 21 题 cost 为 {10,15,20} 时输出 15,判断题正确。第 22 题把dp[i-1]改成dp[i-3],程序可能产生编译错误吗?不会,下标表达式只要类型合法就能编译,答案是错误。第 23 题说程序总是输出 cost 数组最小元素,错误,动态规划求的是路径最小和,不是数组最小值。

第 24 题 cost 为 {1,100,1,1,1,100,1,1,100,1},输出 6,选 A。第 25 题 cost 为 {10,15,30,5,5,10,20},输出 30,选 B。第 26 题把min(dp[i-1],dp[i-2])+cost[i-1]改成dp[i-1]+cost[i-2],输入 {5,10,15},输出 10,选 A。做这类题不要一上来写完整表格,先手算前三项,确认转移方向;再拿题目给的数组逐项推。改转移式后,先看新式子会不会访问负下标,再看它是否还保留“取较小值”的逻辑。

3.3 递归函数阅读:b 为负为什么会无限递归

递归阅读题先找递归基,再找递归步。第 27 题输入 2 3,customFunction(2,3)返回值不是 64,判断题错误。第 28 题 b 为负数时会陷入无限递归,正确。原因很直接:递归步通常让 b 递减,如果递归基只判断 b 等于某个正数或 0,负数永远到不了终止条件,就会一直调用下去。第 29 题 b 越大运行时间越长,正确,因为递归层数增加。第 30 题输入 5 4,返回 25,选 B。第 31 题输入 x=3、y=3,程序最终输出 144,选 C。第 32 题把函数改为return a + customFunction(a-1,b-1);并输入 3 3,最终输出 36,选 D。

递归题最稳的答题方式是画调用表:第一列写调用参数,第二列写返回值,第三列写是否触发递归基。遇到“改递归式”的题,先看递归基有没有跟着改;遇到“负数”的题,先问递归变量是不是单调递减;遇到“运行时间”的题,看递归层数和每层循环次数。不要凭直觉估一个数,递归题的选项往往就是按常见错误设计的。

3.4 阅读程序判断题的答题模板

阅读程序判断题可以固定走四步。第一步,标出程序功能,用一句话写在草稿纸上,比如“统计素数和”“爬楼梯最小花费”“递归求幂或累加”。第二步,找边界:输入 0、1、2、负数、空数组时程序怎么走。第三步,看改动:题目把哪个条件、哪个下标、哪个返回值改了,只改一处还是连带改。第四步,验证选项:拿题目给的小输入手算,不要拿大输入硬推。判断题 1.5 分,选择题 3 分,先拿稳判断题,再攻选择题。阅读程序题里最值钱的动作不是读得快,而是把边界用例写下来。

4. 完善程序题:平方数判断与汉诺塔的填空套路

完善程序 30 分,通常两段程序、每空 3 分。2024 年这套题第一段判断完全平方数,第二段汉诺塔递归。完善程序不是完形填空,不能靠语感,要靠变量角色:这个变量是循环起点、上界、比较对象还是返回值?这个递归函数的三根柱子分别代表源、辅助、目标中的哪一个?把角色表写出来,选项会自己缩小。

4.1 判断平方数:枚举上界、比较条件、返回布尔

题面程序要判断正整数 n 是不是完全平方数,也就是是否存在正整数 x 使 x²=n。补全后的核心代码如下:

bool isSquare(int num) { int i = 1; // ① 从 1 开始枚举 int bound = (int)floor(sqrt(num)); // ② 枚举上界取 sqrt(num) for (; i <= bound; ++i) { if (num == i * i) { // ③ 判断是否等于平方 return true; // ④ 找到就返回真 } } return false; // ⑤ 没找到返回假 }

第 33 题①处填 1,选 A。第 34 题②处填(int)floor(sqrt(num)),选 B。第 35 题③处填num==i*i,选 D。第 36 题④处填true,选 C。第 37 题⑤处填false,选 D。这段程序的参数是num,i是枚举变量,bound是上界。为什么上界取 sqrt(num)?因为如果 i 超过平方根,i² 一定大于 num,再枚举没有意义。为什么从 1 开始?因为题目说正整数 x,1 的平方是 1,不能从 2 开始漏掉 1。比较条件必须用==,写成=是赋值,逻辑直接错。

提示:完善程序里出现=和==的选项,先看它是判断还是赋值;出现i*i和2*i的选项,先问程序在判断平方还是偶数。

4.2 汉诺塔递归:三根柱子的角色轮换

汉诺塔的规则是每次移动一个圆盘,小盘必须在大盘之上,目标是把 n 个盘从源柱移到目标柱。补全后的递归框架如下:

void dfs(int i, char src, char tmp, char tgt) { if (i == 1) { // ① 只剩一个盘,直接移动 move(src, tgt); // ② 从源柱移到目标柱 return; } dfs(i - 1, src, tgt, tmp); // ③ 先把上面 i-1 个盘移到辅助柱 move(src, tgt); // 把最大盘移到目标柱 dfs(i - 1, tmp, src, tgt); // ⑤④ 再把 i-1 个盘从辅助柱移到目标柱 }

第 38 题①处填 1,选 B。第 39 题②处填src,tgt,选 B。第 40 题③处填src,tgt,tmp,选 B。第 41 题④处填tmp,src,tgt,选 B。第 42 题⑤处填i-1,选 C。参数i是当前要移动的盘数,src是源柱,tmp是辅助柱,tgt是目标柱。递归基是只剩一个盘,直接move(src,tgt)。递归步分三拍:先把上面 i-1 个盘从 src 借助 tgt 移到 tmp;再把最大的盘从 src 移到 tgt;最后把 i-1 个盘从 tmp 借助 src 移到 tgt。参数顺序一抄反,整段递归就翻车。

4.3 完善程序如何用“变量角色表”排除选项

完善程序题可以固定做一张小表:

空位要填的角色判断方法
循环起点从 0 还是 1 开始看题目是否包含 0 或 1
循环上界sqrt、n/2 还是 n看枚举范围是否覆盖答案
比较条件==还是=看是判断还是赋值
返回真找到目标时返回看函数名和题意
返回假循环结束仍未找到看是否要兜底
递归基i==1 还是 i==0看最小规模是否可直接移动
递归参数src、tmp、tgt 的顺序看“借助谁、移到谁”

汉诺塔这种题,先把三根柱子的角色写成一句话:“把 i 个盘从 src 借助 tmp 移到 tgt。”再把这句话拆成三步,选项里谁的参数顺序符合这句话,就选谁。平方数这种题,先问“枚举到哪停”,再问“怎么判断相等”,最后问“找到和没找到分别返回什么”。完善程序不需要你现场发明算法,只需要你把题面已经搭好的骨架补完整。

5. 易错点:初赛最常见的 5 个失分点

5.1 把“二分最多比较次数”当成不取整的 log

错在哪:1000 个元素,有人算出 log2 1000 约等于 9.96,看到选项 10 觉得“约等于”,看到 7 又觉得“2^7=128 差不多”,最后选错。为什么错:二分查找最多比较次数要按“每次折半,直到区间为空”算,1000 个元素最多 10 次,答案选 B。怎么答对:先写 2^9=512、2^10=1024,1000 落在两者之间,最多 10 次;如果题目问“最少”或“平均”,再换口径。有序表二分题不要凭感觉,先看 2 的幂次。

5.2 栈的出栈序列只盯一个元素

错在哪:第 13 题 D 项 1 3 5 2 4 6,有人看到 1 先出、3 后出觉得“可以”,没继续模拟到 2。为什么错:5 出栈后,栈里还有 2、3、4,栈顶是 4,2 被压在下面,不能先于 4 出。怎么答对:画栈,按目标序列逐个模拟;目标元素没入栈就继续入栈,已入栈但不在栈顶就判非法。口诀是“大元素出栈后,小元素不能隔着栈顶跳出来”。

5.3 阅读程序把“改条件”当成原程序

错在哪:第 20 题把i*i<=n改成i<=n,有人直接套原程序答案“4 和 17”,选了 B。为什么错:改条件后isPrime(2)会在 i=2 时发现 2%2==0,把 2 误判为非素数;isPrime(3)也会在 i=3 时误判。怎么答对:改条件后强制跑 n=2、n=3、n=4 三个边界,再看选项。阅读程序题只要出现“如果将……改为……”,就把原答案清零,重新模拟。

5.4 组合计数漏掉“哪个部门出 2 人”的分类

错在哪:第 3 题只算 A 部门出 2 人的 54 种,或者把三类乘起来,得到 54 或更大的数。为什么错:4 人分到 3 个部门,出 2 人的部门可能是 A、B、C 中任意一个,这是分类,不是分步,三类要相加。怎么答对:先写“必然有一个部门出 2 人”,再列三类,分别算完相加。女生相邻题同理,捆绑后别忘了乘 3! 的内部排列。

5.5 完善程序把递归参数顺序抄反

错在哪:汉诺塔第 40 题③处,有人填src,tmp,tgt,第 41 题④处也照抄,结果递归方向全反。为什么错:第一步是“把上面 i-1 个盘从 src 借助 tgt 移到 tmp”,参数顺序应是src,tgt,tmp;第三步是“从 tmp 借助 src 移到 tgt”,参数顺序应是tmp,src,tgt。怎么答对:每写一个递归调用,先读一遍“从哪、借助谁、到哪”,再对参数。递归题不靠背选项,靠角色表。

6. 考场答题技巧:选择题、阅读程序、完善程序的检查顺序

考场时间建议这样切:前 12 分钟做 15 道选择题,不会的先标记,别恋战;第 12 到 30 分钟攻阅读程序,先做判断题,再做选择题;第 30 到 50 分钟做完善程序,每空先写角色,再选选项;最后 10 分钟检查边界和填涂。选择题的检查重点是 int 端点、存储单位、组合分类、栈序列;阅读程序的检查重点是“改条件后有没有重新跑边界”;完善程序的检查重点是递归参数顺序和返回真假。

阶段时间动作检查点
选择题0-12 分钟先易后难,标记不确定int 范围、进制转换、组合分类
阅读程序判断12-20 分钟先看问题再读代码边界用例 0、1、2、负数
阅读程序选择20-30 分钟手算小输入改条件后重新模拟
完善程序30-50 分钟写变量角色表循环起点、上界、递归参数
检查50-60 分钟回看标记题填涂是否错位、选项是否抄反

押题思路不复杂:选择题优先保 int 范围、存储换算、进制、组合、二叉树、栈、二分、图度数和;阅读程序优先保素数统计、动态规划转移、递归基;完善程序优先保平方数枚举、汉诺塔递归、二分边界。血泪经验是,阅读程序题最怕“看一眼觉得是原题”就选答案,改条件题必须重跑边界。从那以后我每次拿到阅读程序题,都先在草稿纸写“输入 2、3、4 会怎样”,再去看选项。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询