☰
CSP-J初赛100分题型考点与失分点备考指南
2026/10/27 11:29:06 网站建设 项目流程

简介:面向备战信息学奥赛CSP-J入门组初赛的学生、少儿编程教师及陪练家长,这份2024年真题详细分析以单份docx文档呈现,压缩包仅121KB,共1个文件,便于在电脑或平板上直接查阅。文档围绕2024年CSP-J第一轮试题展开,逐题给出答案与解析,覆盖32位int存储范围、二进制与十六进制换算、格雷码、组合计数、二分查找、栈的出栈序列、无向图度数性质、二叉树前中后序遍历、操作系统与编译器基础等高频考点,并延伸到阅读程序题的代码理解与算法推理。读者可借助它核对答案、定位知识薄弱点,按“基础知识—算法数据结构—数学逻辑—C++语言”的顺序整理错题,形成可复用的初赛复习清单。已有2594人学习,适合作为赛前自测与教师讲评的参考材料。

1. 从一道int范围题说起:CSP-J初赛100分是怎么分布的

2024年CSP-J初赛第一题问32位int的存储范围,四个选项里只有C是-2147483648到2147483647。两分题,位置在最前面,可每年都有人在这里翻车:凭"正负对称"的直觉勾了-2147483647到+2147483647,忘了补码表示下负数比正数多一个。这道题把整场考试的取向摆得很清楚——入门组初赛不考你能不能独立写出完整程序,考的是你对计算机基本规则的记忆精度,以及读别人代码时眼睛够不够细。整卷100分,单项选择题15题30分,阅读程序3篇约40分,完善程序2篇10个空30分。目标人群也很明确:小学高年级到初中、第一次报C++信息学奥赛入门组的考生,或者去年差几分卡在分数线下的复读型选手;少儿编程学到能写循环和递归的阶段,就该拿真题来校准自己的位置了。

2. 单项选择题:15道题30分的考点地图与必背数据

选择题是整卷里唯一"不会也能蒙"的部分,但它同时是拉开差距最快的地方——前五题稳拿,后面几题靠的是有没有把结论背成条件反射。2024年这套题的15个小题,摊开来看并不散,集中在五块:计算机基础常识、进制与存储换算、排列组合计数、线性与树形数据结构、C++语言本身的语法边界。

2.1 十五道题各自的考点与死结论

先把这张表记住,它是后面所有练习的索引。你会发现没有一道题需要现场推导超过三步,全是"记得住就秒选,记不住就干瞪眼"的类型。

题号考点必须背下来的结论
132位int范围-2147483648 ~ 2147483647,负数多一个
2进制混合运算先全部转十进制再算,答案是13
3分组组合计数每部门至少1人,必有一部门出2人,54+36+36=126
4格雷码相邻两个编码只有一位不同,选D
5存储单位换算1MB=1024×1024×8=8388608 bit
6基本数据类型struct是复合类型,不是基本类型
7循环语句C++只有for、while、do-while,没有repeat-until
8字符与ASCII'a'+13='n',往后数第13个字母
9二分查找比较次数对1000取以2为底的对数向上取整,得10次
10操作系统识别Notepad是记事本软件,不是操作系统
11无向图度数所有顶点度数之和等于边数的两倍
12二叉树遍历还原前序定根、中序分左右,后序为D E B F G C A
13栈的出栈序列1 3 5 2 4 6不可能,画栈即知
14相邻元素捆绑6个整体全排列乘3个女生内部排列,720×6=4320
15编译器职责把源代码翻译成机器代码,不是执行也不是调试

这张表里最值得反复看的是9、11、14三行。它们分别代表了初赛最爱出的三种"公式型"考点:对数、图论恒等式、排列组合。公式记错一个符号,后面的计算全废。

2.2 八个数必须背到不用想

选择题里有相当一部分,本质是考"你有没有把这几个数刻进脑子"。考场上一秒钟能反应的,和现场拿笔算的,做题速度差三倍。

  • int占4字节共32位,取值范围-2³¹到2³¹-1;unsigned int则是0到2³²-1。
  • 1KB=1024B,1MB=1024KB=2²⁰B,换算成二进制位再乘8,即8388608。
  • 二分查找对n个有序元素,最多比较⌈log₂n⌉次;1000对应10,100对应7。
  • 无向图所有顶点度数之和=2×边数;有向图则是入度之和=出度之和=边数。
  • ASCII码:'0'是48,'A'是65,'a'是97,大小写字母相差32。
  • C++基本数据类型八种:int、char、float、double、bool、short、long、long long(还有它们的有符号/无符号变体),struct、union、enum、class都不算。
  • 三种循环语句加break、continue,没有repeat-until,那是Pascal的写法。
  • 常见操作系统:Windows、Linux、macOS、Unix,记事本、画图、计算器都是应用软件。

提示:这几条不要只背结论,要连着"常见的错误选项长什么样"一起背。比如int范围题的错误选项一定是把负端点写成-2147483647,识别出这个套路比记数字更管用。

2.3 组合计数与二叉树:把看起来难的两道题拆成小步

第3题是最容易做错的一道。10名员工分在三个部门(4人、3人、3人),选4人组队且每部门至少1人。很多人第一反应是C(10,4)=210,然后发现选项里没有,慌了。正确思路是先判断结构:4个人分给3个部门且每部门至少1个,人数分配只能是2+1+1,那个"2"可能落在任何一个部门。于是分三种情况分别算:A部门出2人时C(4,2)×C(3,1)×C(3,1)=54;B部门出2人时C(4,1)×C(3,2)×C(3,1)=36;C部门出2人时同理36。三类互斥,用加法原理合并,54+36+36=126。

这道题的答题模板可以固化下来:先定"人数分配形态",再定"哪个组承担多出来的名额",最后分类相乘、跨类相加。凡是看到"每组至少一个"的字样,一律先想这个结构,不要直接套组合数公式。踩坑最多的就是只算了一种情况就填答案,54在选项里根本没有,但108、126这种"看起来接近"的数很容易骗人。

第14题反过来简单:5男3女排成一排,3个女生必须相邻。捆绑法,把3个女生捏成一个整体,与5个男生共6个对象全排列是A(6,6)=720,女生内部还有A(3,3)=6种顺序,相乘得4320。这类题的关键动作只有一个——先问"捆绑的是谁",再问"捆绑体内部要不要再排"。

第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说明B是左子树根,中序D B E说明D在B左、E在B右;右子树同理,C为根、F在左、G在右。最后按"左、右、根"输出:D E B F G C A。手写时建议在纸上画树,画完再写后序,比在脑子里转要稳。

第13题判定不可能的出栈序列,方法是拿一支笔模拟栈。以D选项1 3 5 2 4 6为例:1进1出,2进3进3出,4进5进5出,此时栈内从底到顶是2、4,栈顶是4,想弹2根本弹不出来。判断栈序列题的通用手法就是"目标元素不在栈顶就必须继续入栈,直到它出现;如果剩余入栈元素已经用完它还不在栈顶,这个序列就不可能"。血泪经验是:不要凭"感觉差不多"选,一定要在草稿纸上画那几根竖线。

3. 阅读程序:三篇代码的判对错套路与改条件推演

阅读程序占40分,是三块里分值最高、也最容易"会读但做错"的部分。它的题面结构固定:给一段完整代码,先三道判断题(对错),再两道选择题(其中常有一道4分)。判断只问"输出是不是这个值""这行改动会不会报错""这个函数是不是干这个的",选择则往往是把某一行改掉,问新输出。

3.1 三篇程序各自的骨架,先认脸再动笔

2024年这三篇的骨架非常典型,认出类型就能预判考点。

第一篇是素数三件套:isPrime判断单个数、countPrimes统计个数、sumPrimes求和。它考的是循环边界i*i<=n和函数职责划分。

第二篇是线性动规,形如dp[i]=min(dp[i-1],dp[i-2])+cost[i-1],考的是下标含义、初值设定、以及改动下标后是否越界。

第三篇是递归函数customFunction,涉及递归深度和参数递减,考的是"b为负数会怎样""b越大跑得越久"这类边界与复杂度问题。

#include <iostream> using namespace std; bool isPrime(int n) { if (n <= 1) return false; // 0和1不是素数,这个边界必须留 for (int i = 2; i * i <= n; i++) { // 只需试到根号n,写成i<=n会慢且结论错 if (n % i == 0) return false; } return true; } int sumPrimes(int n) { int sum = 0; for (int i = 2; i <= n; i++) { // 从2开始,1不参与累加 if (isPrime(i)) sum += i; } return sum; }

这段代码的关键在两处注释。第一处i*i<=n决定了时间复杂度是O(√n)而不是O(n);第二处i<=n的循环起点是2,如果从1开始,sumPrimes会把1算进去导致结果偏大。第三处是n<=1的提前返回,缺了它,isPrime(1)会返回true。

3.2 判断题:先问"这个函数干什么",再问"边界改了会怎样"

第16题输入10,问countPrimes是否输出4、sumPrimes是否输出17。10以内的素数是2、3、5、7,个数4,和17,判断题正确。这类题的唯一解法是老老实实列出来,别估算。

第17题问:把isPrime里的条件i*i<=n改成i<=n/2,输入20时countPrimes(20)的输出是否变成6。这里就是最容易翻车的地方——很多人以为改了循环条件判定结果就变了,其实i<=n/2依然能覆盖n的所有真因子(除n本身外的因子最大不超过n/2),所以判素结论完全不变,输出还是8。判断给的是"变为6",所以填错。玄学感就在这儿:改了代码,结论却没变。

第18题问sumPrimes是不是计算2到n之间所有素数之和,看函数名和循环起点就能确认,正确。

这三道题连起来看,判断题的答题顺序应该是:先确认函数整体在算什么(这一步能拿下18题这种送分题),再逐行抠边界(拿下16题),最后才去推"改一处会怎样"(17题)。顺序反过来,容易被细节拖着走。

3.3 选择题:一行改动引发的连锁反应

第19题问sumPrimes(50)的输出。这题没有捷径,必须列素数表:2、3、5、7、11、13、17、19、23、29、31、37、41、43、47,累加得328,选B。考场上的省时办法是分组累加:2+3+5+7=17,11+13+17+19=60,23+29=52,31+37=68,41+43=84,47单独,加起来17+60+52+68+84+47=328。分组能减少心算出错的概率。

第20题更狠:把i*i<=n改成i<=n,问输入10时输出什么。改动之后,isPrime(n)在i循环到n时会遇到n%n==0,于是所有数都被判成非素数,countPrimes输出0、sumPrimes输出0,程序彻底不能正确工作,选A。这道题的陷阱在于选项里有一项"仍然输出4和17",专治"改了代码但懒得重算"的考生。

读懂改动的连锁反应,有个通用检查顺序:一看改动在哪个函数,二看这个函数被谁调用,三看调用处的输入范围是否会触发新边界。第20题的改动在isPrime,而isPrime被两个函数调用,范围都覆盖到n本身,所以连锁反应是全局性的。

3.4 手算这类题的三个小工具

不用工具硬算,40分的阅读程序能把你耗到没时间写后面的完善程序。三个小工具:一是素数表背到50以内,2、3、5、7、11、13、17、19、23、29、31、37、41、43、47,考试时直接抄;二是递推题列表格,把i、dp[i]两列画出来逐行填,比脑内推演可靠;三是递归题画展开树,customFunction(a,b)每层把参数写下来,三五层就能看出规律。这三招没有技术含量,但能保证你会做的题不丢分。

4. 完善程序:十个空位的定位逻辑与递归参数对位

完善程序两篇各5空,每空3分共30分。它的形式和阅读程序相反:代码骨架给你,关键位置挖空,让你从四个选项里选出正确填法。这类题的核心不是"想出来",而是"用上下文反推"——每个空位的答案,几乎都能从它前后的变量名、循环条件、返回值类型里读出来。

4.1 判断平方数:五个空其实只有三个决策点

这篇程序要判断正整数n是否为完全平方数,思路是从1枚举到√n,看有没有i满足i×i==n。五个空看似分散,实际只有三个决策点:枚举起点、枚举上界、命中与未命中的返回。

第33空是int i = ①,起点。既然是判断完全平方数,从1开始枚举最自然,选A。

第34空是int bound = ②,上界。四个选项都在floor和sqrt上做文章:(int)floor(sqrt(num)-1)、(int)floor(sqrt(num))、floor(sqrt(num/2))-1、floor(sqrt(num/2))。正确上界是√num向下取整,选B。这里的判断依据是:如果i能超过√num还满足i×i==num,那num就不是完全平方数了,所以枚举到√num足够。

bool isSquare(int num) { int i = 1; // 从1开始枚举 int bound = (int)floor(sqrt(num)); // 上界取根号num的整数部分 for (; i <= bound; ++i) { // 注意sqrt要包含cmath头文件 if (num == i * i) { // 判定用==而不是= return true; // 命中即返回真 } } return false; // 循环走完没命中,说明不是平方数 }

这段代码里有两个细节值得单独说。一是num == i * i而不是num = i * i,赋值和判断在C++里差一个等号,选项里专门放了这个混淆项;二是floor(sqrt(num))必须转成int,因为sqrt返回浮点数,直接拿来当循环上界会有精度问题。参数num的类型是int,若num为0或1,bound分别是0和1,循环行为依然正确,这也是为什么起点选1而不是0不会出错。

第35空是判定条件,选num == i*i;第36空是命中后的返回,选true;第37空是循环结束后的返回,选false。这两空最容易搞反——记住一个口诀:循环里面的return是"找到了",循环外面的return是"找完了也没有"。

4.2 汉诺塔:递归三参数的对位法

汉诺塔这篇的难点不在算法思想,而在递归调用时三个柱子参数的顺序。很多人算法背得滚瓜烂熟,一到填参数就全乱。

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个从辅助柱挪到目标柱 }

参数含义:i是待移动的盘子数,src是源柱,tmp是辅助柱,tgt是目标柱。第38空if(i == ①)填1,因为只有一个盘子时不需要再递归,直接搬。第39空move(②)填src, tgt,把唯一的盘子从源搬到目标。第40空是第一次递归dfs(i-1, ③),此时要把i-1个盘子从src搬到tmp,tgt充当辅助,所以三个参数依次是src、tgt、tmp。第41、42空是第二次递归dfs(⑤, ④),从tmp搬到tgt,src当辅助,即dfs(i-1, tmp, src, tgt),所以④填tmp、src、tgt,⑤填i-1。

对位方法可以固化成一个动作:每次写递归调用前,先在纸上写"我要把__个盘子从__柱,借助__柱,搬到__柱",然后按这个语序把三个字母填进去。汉诺塔的递归永远满足"搬n-1个→搬最大的→搬n-1个"这个三段式,中间那一步是move(src, tgt),前后两步的参数正好是交换关系。把这个结构记牢,考场上看一眼就能填完。

4.3 完善程序的通用检查顺序

填完不要立刻下一题,按这个顺序过一遍:第一,把填好的代码通读,看有没有变量未定义、类型不匹配;第二,拿最小的输入试跑,比如n=1、n=0,看会不会越界或死循环;第三,检查循环边界是<还是<=,这是选项最爱做手脚的地方;第四,确认return语句在循环内还是循环外。四步走完,30分里该拿的基本能拿住。

5. 失分点归因:五类最容易在初赛翻车的题

5.1 概念型失分:三个"想当然"

第一个想当然是把int范围记成对称的-2147483647到2147483647。错在把补码当成原码理解,补码里0占了一个正数位,负数就多出一个。怎么答对:记住"-2³¹到2³¹-1"这个式子,负数端点是2的幂,正数端点要减1。

第二个想当然是把1MB当成1024×1024个二进制位。错在混淆Byte和bit,题目问的是二进制位,得再乘8。怎么答对:读题时把单位圈出来,看到"bit"就在草稿上写×8,看到"Byte"就停。

第三个想当然是看到int、float、char就顺手把struct也划进基本类型。错在把"常用"当成"基本",struct是复合类型,是把基本类型打包用的。怎么答对:背那句"基本类型是编译器自带的、不能再拆的",struct、union、enum、class一律排除。

5.2 计算型失分:两个高频翻车现场

组合计数漏情况。第3题只算A部门出2人的54种就交卷,忘了B、C两种对称情况。错在把"某一个部门"当成"指定的部门",题干说的是"每个部门至少1人",没有指定谁出2人。怎么答对:凡是出现"至少一个"的分组题,第一步就写"必然有一个组多承担k个",然后把每个组轮流当主角列一遍,最后相加。

二分查找次数取整方向搞反。1000个元素,有人算出log₂1000≈9.97,向下取整填9。错在没理解"最多比较次数"是保证能查到的上界,必须向上取整。怎么答对:记结论⌈log₂n⌉,配合2¹⁰=1024>1000来验证,10次够、9次不够。

5.3 读程序失分:三个致命习惯

只扫代码不跟数据。看阅读程序题时眼睛从main扫到return,自以为懂了,一填就错。错在读代码和跑代码是两件事,不跟着具体输入走一遍,永远不知道边界在哪。怎么答对:拿题给的输入,在草稿上列一张变量表,逐行更新,尤其是循环变量和累加变量。

改了条件还按原结论填。第17、20题都是改动型,考生心里默认"改一下应该差不多",结果全反。错在没有重新推演。怎么答对:看到"如果将……改为……",先把这个改动单独抄在草稿纸上,再问自己三个问题——改动影响哪个变量、这个变量被谁用、用它的时候范围是多少。

递归题不展开。customFunction(a,b)这类题,凭"感觉它会递归b次"就下判断,遇到b为负数直接懵。错在没验证递归终止条件。怎么答对:把b=0、b=1、b=-1三种情况代进去看会不会停,只要有一路不停,就是无限递归。

6. 考场节奏与押题:一套能照做的三遍答题流程

初赛90分钟做100分,时间不算紧,但很多人栽在节奏上——前面选择题磨太久,最后完善程序只剩十分钟。我的建议是把卷子切成三段,按分值配时间。

轮次内容时间目标
第一遍15道选择题20分钟会做的立刻选,卡住超过1分钟的直接标记跳过
第二遍两篇阅读程序30分钟先做判断再做选择,手算题列表格
第三遍两篇完善程序25分钟用上下文反推空位,填完按四步检查
回看标记题与易错点15分钟只改有明确理由的题,不改"感觉不对"的题

押题方向上,2024这套卷给出的信号很清楚:int范围、存储换算、二分次数、图论度数、栈序列、二叉树还原、组合计数这七类,几乎是每年必出现的固定班底;阅读程序偏爱素数、递推、递归三种骨架;完善程序偏爱"枚举+边界判定"和"经典递归"两种题型。复习时不用铺得太开,把这七类结论背熟、三种骨架读透,过线的把握就很实。

我自己备考那年,最深刻的一课来自第17题——我在模拟时选了"输出变为6",对答案才发现改了循环条件判定结果压根没变。从那以后我每次遇到"如果将……改为……"的题,都强制走一遍"抄改动、找影响、代输入"三步,哪怕心里已经有答案。这个习惯后来帮我在正式考试里救回了两道选择。希望帮到你。

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

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

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

立即咨询