简介:2024年海淀区中小学生信息学竞赛校级预选赛试题以单份PDF形式呈现,面向准备参加信息学竞赛的中小学生及指导教师,聚焦编程基础知识与程序阅读能力的赛前自测。资源包内共1个PDF文件,约422KB,内容按“编程基础知识单选题”和“程序阅读单选题”两部分组织,题目覆盖变量命名、赋值语句、二进制与十进制转换、表达式运算、逻辑判断、函数定义与调用、循环语句、数组等考点,并配有若干段C++程序供推断输出结果,题型紧凑,便于分模块练习。已有588人学习,适合用于熟悉题型、定位知识薄弱点和教师挑选例题。通过限时练习、错题归类和逐题复盘,读者可系统梳理竞赛基础概念,训练代码阅读与逻辑推理能力,为校级预选赛及后续进阶做好准备。
1. 先看清卷面:校级预选赛的分数,多半丢在“读题”而不是“算法”
2024年某区中小学生信息学竞赛校级预选赛的卷子,最容易让人误判的一点是:它看起来像编程题,实际先用三类单选筛人。第一类是编程基础知识,变量命名、赋值写法、进制转换、表达式结果、数组初始化、循环与函数概念;第二类是程序阅读,给一段 C++ 代码问输出;第三类是问题阅读,用屏幕滚动、视频压缩、掷骰子、爬山记录这类故事包装计数与模拟。想拿分,顺序不是上来就啃长题干,而是先把基础单选和短代码阅读的稳定分收住,再用“变量表+边界值”拆长题。适合刚学完 C++ 语法、能做简单循环和数组、准备校级预选赛的学生;也适合家长帮孩子判断薄弱模块。最容易翻车的地方,是把程序阅读当“凭感觉看代码”,把问题阅读当“数学大题”硬算。实际考的是人肉解释器能力和把故事翻译成变量关系的能力,先把这两件事练顺,分数才会稳。
2. 基础单选:变量、赋值、进制与表达式的送分点怎么拿
2.1 变量命名与赋值语句:先排除“看起来像代码”的选项
变量命名题不考英文水平,考的是 C++ 的硬规则:名字只能由字母、数字、下划线组成,首字符不能是数字,不能是关键字,不能带空格、减号、点号、引号。很多选项故意写成2a、int、a-b、a b这种“像名字但一读就违规”的形式。答题时不要凭印象,按“首字符—字符集—关键字”三步扫一遍,三步都过才是合法变量名。
赋值语句题更容易埋坑。赋值号左边必须是一个可修改的变量,不能是常量、表达式或带引号的字符串;语句末尾要有分号;字符串用双引号,单个字符用单引号。题目里出现5=a;、a+b=3;、"abc";、'a';这类写法,先看左边能不能被赋值,再看引号类型和分号。下面这张表可以直接拿来排查。
| 检查点 | 合法样子 | 常见错误样子 | 答题动作 |
|---|---|---|---|
| 首字符 | a1、_sum | 1a、$x | 首字符必须是字母或下划线 |
| 关键字 | score | int、for | 对照关键字表排除 |
| 特殊符号 | max_value | a-b、a.b | 只允许字母、数字、下划线 |
| 赋值左边 | a=3; | 3=a;、a+b=1; | 左边必须是变量 |
| 引号 | "abc"、'a' | 'abc'、"a"混用 | 字符串双引号,字符单引号 |
提示:赋值语句题不要先算右边,先看左边是不是“能装东西的变量”,这一步能排掉一半错误项。
2.2 进制转换与表达式求值:把“符号优先级”写在草稿上
二进制转十进制按权展开:从右往左第 0 位乘 (2^0),第 1 位乘 (2^1),依次相加。遇到1011这种短串,直接写1×8 + 0×4 + 1×2 + 1×1 = 11,比在脑子里跳更快。反过来十进制转二进制用短除法,从下往上读余数。进制题通常不难,错在把权位从左边开始数,或者把2^0当成 0。
表达式求值题考三件事:运算符优先级、整数除法与取余、关系与逻辑运算的结果。算术运算符先乘除后加减,括号最优先;赋值运算符从右往左结合;关系表达式的结果是逻辑值,在 C++ 里通常表现为0或1;逻辑与、逻辑或存在短路求值。字符型变量可以参加算术运算,参与的是字符对应的编码值,不能因为它叫“字符型”就认定不能算。遇到自增自减,先标出变量当前值,再按表达式顺序走,不要跳步。
答题时可以在草稿上写两行:第一行写变量初值,第二行写每一步运算后的值。比如表达式里同时有%、/、*,先把%和/按从左到右结合算清,再算加减。遇到a++和++a,先判断题目问的是表达式值还是变量最终值,这两个问法经常被混在一起。
2.3 分组、排序比较与数组初始化:用枚举和小数据验证
分组题的关键是“人数差不能超过某个值”,不是“每组人数必须相等”。总人数固定、组数固定时,先写出平均分法和余数,再把余数分给不同组,枚举出所有满足差值限制的组合。题目给的具体人数在卷面上,方法不变:设三组人数为 (x,y,z),满足 (x+y+z=N),且任意两组差不超过给定值,逐个枚举 (x) 后检查 (y,z)。这种题最怕凭感觉写一个“平均分”,结果漏掉差值边界。
排序比较次数题先看题目问的是哪种排序。以最简单的冒泡排序或选择排序为例,最坏情况下比较次数通常是 (n(n-1)/2);插入排序最坏也是这个量级。题目给“给定 (n) 个正整数,从小到大排序,最坏需要多少次比较”,先把 (n) 代入公式,再看选项里有没有“正好等于”或“不超过”的表述。若题目问的是“至少”或“最多”,边界会差一次,答题时把 (n=3) 的小例子手算一遍验证。
二维数组初始化题按行优先填。int a[3][2]={2,3,4,5,6,7}的含义是:第一行a[0][0]=2、a[0][1]=3;第二行a[1][0]=4、a[1][1]=5;第三行a[2][0]=6、a[2][1]=7。所以值为 5 的元素是a[1][1]。这类题不要数“第几个”,要写“行号、列号”两个下标,再对照初始化列表的位置。
循环与函数概念题也常放在基础单选里。for可以实现确定次数循环,也可以配合条件实现不确定次数;while同样两种都能做,不能说“while专用于不确定次数”。break跳出整个循环,continue只跳过本次循环剩余部分。函数方面,C++ 程序有且只有一个main函数作为入口;函数可以自己调用自己,这叫递归;C++ 不支持在函数内部再定义函数,但可以在函数内部调用其他函数。题目问“错误说法”时,重点抓“专用于”“必须”“有且只有”这类绝对词,再逐个对照规则。
3. 程序阅读:八道代码题用“变量追踪表”拆开
3.1 先搭拆解框架:输入、初值、循环边界、输出
程序阅读不是让你在脑子里运行完整程序,而是让你当一次“人肉解释器”。拿到代码先做四件事:圈出输入变量,标出所有变量的初值,写清循环的起点、终点和步长,最后锁定输出语句。循环边界是最大的失分点,i<n和i<=n差一次,i=1和i=0差一轮,break出现的位置又会让循环提前结束。下面这张表可以在草稿上直接画。
| 追踪项 | 要写什么 | 作用 |
|---|---|---|
| 输入 | 变量名、题目给的样例值 | 防止把输入变量和计数器混掉 |
| 初值 | 全局变量默认 0,局部变量看定义 | 判断cnt、ans从几开始 |
| 循环 | 起点、终点、步长、条件 | 锁定每一轮i的取值 |
| 跳转 | break、continue在哪一行 | 判断是否提前结束或跳过 |
| 输出 | 输出哪个变量、有没有换行 | 防止算对过程写错答案 |
提示:程序阅读先别急着算结果,先把循环变量
i的取值列成一行:1,2,3,...,n,再逐个代进去,比盯着代码看稳。
3.2 约数、公因数与最大公因数:三题只差一个终止条件
第一道程序阅读统计的是“小于 (n) 的约数个数”。循环写成for(int i=1;i<n;i++),如果n%i==0就cnt++,注意它没有统计 (n) 本身。输入 6 时,i取 1 到 5,能整除 6 的是 1、2、3,输出 3;输入质数时,只有 1 能整除,输出 1;输入 1 时循环不进,输出 0。答题时先看i<n还是i<=n,再看cnt初值是不是 0,最后按小数据代一遍。
第二道程序统计两个数的公因数个数,但加了“满 6 个就停”。循环从 1 到 (n),条件是两个数都能被i整除就cnt++,每轮结束检查cnt==6就break。因此输出不是公因数总数,而是“公因数总数和 6 的较小值”。答题时先求两个数的最大公因数,再枚举它的因数;如果公因数不足 6 个,输出实际个数,够 6 个就输出 6。不要被m和n的输入顺序绕住,条件里两个取模都要成立。
第三道程序先用min(a,b)找较小值,再从较小值往下找第一个能同时整除a和b的数,这个数就是最大公因数d,最后输出a*b/d,也就是最小公倍数。答题时把“往下找第一个”翻译成“最大公因数”,把最后一行翻译成“最小公倍数公式”,比逐轮手算快。若题目给的是两个具体整数,先写gcd,再算a*b/gcd,注意乘法顺序不要先整除导致精度丢失。
#include <bits/stdc++.h> using namespace std; int gcd(int a, int b) { if (b == 0) return a; // 递归出口:余数为 0 时,a 就是最大公因数 return gcd(b, a % b); // 把 b 和 a%b 交给下一层 } int main() { int x, y; cin >> x >> y; // 输入两个整数 cout << gcd(x, y) << endl; // 输出最大公因数 return 0; }这段代码对应程序阅读里的递归求最大公因数题。参数a、b是当前两个整数,b==0是终止条件,a%b是余数。阅读时不要展开太多层,记住“大数放前、小数放后,余数接力”,最后非零的那个数就是答案。若题目问的是最小公倍数,还要补一行x / gcd(x,y) * y,先除后乘可以减小中间值。
3.3 回文数、筛法与素数判断:看懂“标记数组”和“提前返回”
回文数程序把整数反转:s=s*10+(t%10); t/=10;,每轮取最后一位接到反转结果后面,最后比较s==x。主程序从 1 到 (n) 逐个调用f(i),统计回文数个数。答题时注意 0 和个位数都是回文数,反转过程中前导 0 会自然消失,不影响比较。若题目给的 (n) 不大,可以直接列小数据验证;若 (n) 很大,就按“逐位反转、相等计数”写思路,不要硬算。
筛法程序先开一个标记数组a,a[1]=1表示 1 不是素数;然后从 2 开始,若a[i]还是 0,就把i的倍数全部标记为 1。后面的循环a[i]=a[i-1]+(1-a[i]);把标记数组改造成前缀和:素数位置贡献 1,合数位置贡献 0,最后a[n]就是 (n) 以内素数个数。答题时先分清“标记数组”和“前缀计数数组”两个阶段,不要把a[i]当成原数。
素数判断程序用for(int i=2;i*i<=x;i++)试除,能整除就返回 0,否则返回 1。主程序先判断n是否素数,是就输出 1;否则若n是偶数输出 2;否则若n-2是素数输出 2;剩下输出 3。这里有个容易忽略的点:试除函数对 1 或 0 可能返回 1,若题目输入包含 1,要单独看边界。答题时先判断n的奇偶,再看n-2,最后落到 3,不要一上来就套公式。
3.4 递归与“找数”题:把函数调用写成栈
递归题的核心是“每一层把问题变小”。以最大公因数为例,f(a,b)在b==0时返回a,否则返回f(b,a%b)。手算时写两列:当前a、当前b,每次把右边的数移到左边,把余数移到右边,直到右边为 0。不要试图在脑子里同时展开多层,写出三层就能看出规律。
“找数”题用while(1)从 2 开始逐个检查,先跳过不是 7 的倍数的数,再统计 2 到 (i-1) 之间能整除 (i) 的个数,等于 6 就记录并跳出。这里的cnt统计的是“真因数个数”,不包括 1 和 (i) 本身;cnt==6意味着总因数个数为 8。答题时先翻译cnt的含义,再按“7 的倍数、真因数 6 个”两个条件同时筛,不要只盯一个条件。若时间紧,先写小范围手算表,通常很快能锁定答案。
4. 问题阅读:长故事题先翻译成“变量、操作、边界”
4.1 屏幕滚动题:位置和编号分开记
屏幕滚动题的文字很长,核心只有三组变量:应用编号、应用所在位置、当前屏幕号。题目说每个屏幕放 (K) 个图标,第 1 到第 (K) 个位置在第一屏,第 (K+1) 到第 (2K) 个在第二屏,以此类推。启动某个应用时,先找它的位置 (p),目标屏幕号是 ((p-1)/K)(从 0 开始数屏幕),从第一屏滚动到目标屏需要“目标屏幕号”次滚动,再双击一次,所以单次操作数是“屏幕号+1”。启动后菜单自动返回第一屏,下一次又从 0 号屏开始算。
变化规则也要单独记:应用启动后,系统把该应用图标与“前一个应用”的图标位置交换。若启动的应用已经在第一个位置,就不交换。这里最容易错的是把“应用编号”当成“位置编号”:应用编号不变,位置会变;前一个应用指的是位置上的前一个,不是编号减一。答题时画一张位置表,每次启动后只更新两个位置,不要重排整个数组。
| 变量 | 含义 | 更新时机 |
|---|---|---|
id | 应用编号 | 始终不变 |
pos[id] | 该应用当前所在位置 | 启动后可能与前一个位置交换 |
app[pos] | 该位置上的应用编号 | 与pos同步交换 |
screen | 目标屏幕号 | 由(pos[id]-1)/K算出 |
ans | 总操作数 | 每次加上screen+1 |
注意:题目问“完成全部启动需要多少次操作”,要把每次的滚动次数和双击次数都算进去,少加一次双击就会差 (Q)。
4.2 视频压缩题:按时间轴排服务器空闲槽
视频压缩题考的是“多服务器并行+排队”。每个服务器每 (S) 秒压缩 1 分钟视频,同一时间段一个服务器只能压一个视频,同一个视频只能在一个服务器上压。视频按上传时间先后到达,有服务器空闲就立即开始。答题时维护一个“服务器下一次空闲时间”数组,初始全为 0;按上传顺序处理每个视频,选出最早空闲的服务器,开始时间取“该服务器空闲时间”和“视频上传时间”的较大值,完成时间等于开始时间加上“视频长度×S”。
题目里通常会给第 1 个和第 2 个视频长度不同、其余视频长度相同,具体数值在卷面上。不要背数值,记住公式:完成时间 = max(服务器空闲时间, 上传时间) + 长度×S。处理完一个视频后,把该服务器的空闲时间更新为完成时间。最后逐条对照选项,看哪个完成时间说法错误。
| 步骤 | 动作 | 容易错的地方 |
|---|---|---|
| 1 | 读入服务器数、视频数、压缩速度 | 把“每秒压缩多少”和“每段视频多少分钟”混掉 |
| 2 | 按上传顺序排视频 | 打乱顺序会改变排队结果 |
| 3 | 找最早空闲服务器 | 只看第一个服务器会漏并行 |
| 4 | 算开始、完成时间 | 忘记取 max,视频还没上传就开始压 |
| 5 | 更新服务器空闲时间 | 不更新会导致后续全错 |
4.3 骰子与爬山:可能性判断用“上下界+差值约束”
骰子题给 (M) 个骰子,第 (i) 个骰子有 (a_i) 个面,面上标 1 到 (a_i),同时投掷后和为 (S)。判断“某个骰子上的所有数字是否都可能出现”,不要逐个模拟所有组合,用上下界:固定第 (i) 个骰子的值为 (v),其他骰子的和最小是 (M-1),最大是“其他骰子面数之和”。只要存在 (v) 使 (S-v) 落在这个区间,这个 (v) 就可能;若对 (v) 从 1 到 (a_i) 都成立,才是“所有数字都可能”。答题时先算其他骰子的最小和、最大和,再逐个 (v) 检查区间,不要被“同时投掷”吓住。
爬山题给总天数、第 1 天海拔、第 (D) 天海拔,任意连续两天海拔差不超过给定值,问可能到过的最高海拔。最高点通常出现在中间某天,做法是从左往右推“每天最高可能值”,从右往左推“每天最高可能值”,两边取较小值,再在所有天里取最大。因为左边界和右边界都会限制中间高度,只从一边推会高估。答题时先画一条时间轴,把已知两端标上,再按“每天最多升高多少”向中间夹,最后取夹出来的上界最大值。
5. 易错点:五类一看就会、一选就错的题
5.1 变量名题:把“像单词”当成“合法”
错在哪:看到student、score觉得顺眼就选,忽略选项里可能藏着数字开头、关键字或特殊符号。为什么错:C++ 的变量名规则是硬性的,英文单词再像名字,首字符是数字也不合法;int、for这种关键字更不能当名字。怎么答对:按“首字符—字符集—关键字”三步扫,首字符不是字母或下划线直接划掉,出现减号、点号、空格直接划掉,再对照关键字表。三步都过才留。
5.2 赋值语句题:只看右边算得对不对
错在哪:算出右边表达式的值,觉得没问题就选,没看左边是不是变量。为什么错:赋值号左边必须是可修改的左值,3=a、a+b=1这种写法右边再对也不合法;字符串和字符的引号混用也会报错。怎么答对:先看左边是不是单独一个变量,再看引号类型,最后看分号。左边不是变量,直接判错,不用继续算。
5.3 程序阅读题:忽略i<n和i<=n的边界
错在哪:扫一眼循环,觉得“就是统计约数”,没注意循环终点是<n还是<=n,也没注意break在哪一行。为什么错:少一次循环可能少一个约数,break放的位置不同会让计数提前停止,答案差一整个档。怎么答对:把循环变量取值列出来,标清起点、终点、步长;遇到break画一条竖线,问自己“这一轮后面的语句还执行吗”。小数据代一遍,边界立刻现形。
5.4 函数题:把“递归调用”和“嵌套定义”混为一谈
错在哪:看到“函数可以自己调用自己”觉得对,看到“函数不支持嵌套”又觉得矛盾,结果选错。为什么错:递归是“调用自己”,嵌套定义是“在函数里面再定义一个函数”,C++ 不支持后者,但支持前者;主函数有且只有一个,是程序入口。怎么答对:把“定义”和“调用”分开读,出现“函数里面定义函数”才判嵌套,出现“函数调用自身”就是递归。绝对词“有且只有”“都必须”要逐条对照。
5.5 长题干题:把编号当位置、把上传时间当完成时间
错在哪:屏幕题里拿应用编号直接除以每屏容量,视频题里把上传时间当成完成时间,导致整题方向错。为什么错:应用编号和位置是两个变量,位置会交换;上传时间只是到达时间,完成时间还要加压缩时长和排队等待。怎么答对:长题先画两张表,一张记“编号—位置”,一张记“到达—开始—完成”;每次只更新变化的那一格。题干里的“前一个”“返回第一屏”“同一视频只能一个服务器”都要单独标出来,别用生活经验替代规则。
6. 答题技巧:单选稳分顺序与考前检查清单
这场校级预选赛的单选题,稳分顺序可以固定成三步。第一步先做基础单选里的变量命名、赋值语句、进制转换、数组初始化,这些题短、规则硬,适合开场把手感打热;第二步做程序阅读里代码最短的约数、公因数、回文数题,用变量追踪表逐行代值;第三步再啃长题干的问题阅读,先写变量表,再套操作次数或时间轴公式。最后留几分钟回看绝对词和边界,尤其是i<n、i<=n、break、continue、cnt初值这五个位置。
考前检查可以按下面这张清单走,每项只花十几秒,但能挡住大部分低级失分。
| 检查项 | 快速动作 | 常见收获 |
|---|---|---|
| 变量名 | 看首字符、关键字、特殊符号 | 排掉数字开头和关键字 |
| 赋值语句 | 看左边是不是变量、引号对不对 | 排掉常量赋值和引号混用 |
| 进制转换 | 从右往左标权位 | 防止权位从左边数 |
| 表达式 | 标优先级、整数除法、短路 | 防止先算加减 |
| 程序阅读 | 列循环变量取值、标break | 防止差一次 |
| 函数 | 分“定义”和“调用” | 防止递归与嵌套混淆 |
| 长题干 | 编号与位置分开、到达与完成分开 | 防止整题方向错 |
押题思路不用铺太宽:基础单选大概率围绕变量、赋值、进制、表达式、数组初始化、循环与函数概念;程序阅读大概率围绕约数个数、公因数、最大公因数与最小公倍数、回文数、筛法、素数判断、递归;问题阅读大概率围绕“位置交换+操作计数”“多服务器排队”“上下界判断可能性”“两端向中间夹”。把这几类各练三道,比盲目刷十套卷更有效。
我以前图快,程序阅读总爱直接看最后一行输出,结果在一道i<n的约数题上少算了一个数,整道题翻车。从那以后我每次模考都强制走一遍“先标变量、再走边界、最后回代”的流程,长题干也先画表再动笔,后悔药少吃了很多。这份试题和配套的拆解笔记我放在资源页,按需取用;希望帮到你。
本文还有配套的精品资源,点击获取