首页 / 资讯中心 / 文章详情

信息学竞赛校级预选赛试题PDF拆解:程序阅读、问题阅读与错题模板

信息学竞赛校级预选赛试题PDF拆解:程序阅读、问题阅读与错题模板 ★ FEATURED ARTICLE
简介2024年海淀区中小学生信息学竞赛校级预选赛试题PDF面向备战海淀区信息学竞赛的中小学生及指导教师可用于熟悉校级预选赛题型、检测编程基础与代码阅读能力。压缩包共1个文件为PDF格式大小约422KB便于直接打印或在线查阅。试题分为编程基础知识单选题和程序阅读单选题覆盖变量命名、赋值语句、数据类型、二进制与十进制转换、表达式与逻辑判断、函数定义与调用、循环语句、数组等知识点并通过给定程序片段推断运行结果训练代码跟踪与算法思维。其中程序阅读题涉及约数个数统计、最大公约数与最小公倍数、回文数判断、素数筛法等内容能帮助读者检验对程序结构和边界条件的理解。已有582人学习适合作为赛前模拟练习和知识查漏补缺的专项材料。1. 先翻程序阅读再刷单选2024年某区中小学生信息学竞赛校级预选赛试题PDF的拆解顺序很多同学拿到2024年某区中小学生信息学竞赛校级预选赛试题PDF第一反应是从第一道单选顺着刷。我的建议相反先翻程序阅读和问题阅读用输出倒推基础单选该补哪一块。校级预选赛的分差往往不在会不会写for而在读代码时能不能稳住变量状态、在长题干里能不能把编号和位置分开。这份试题PDF把基础语法、代码推演和场景建模放在同一套卷子里适合做“先诊断、后补模板”的训练不适合只当普通选择题刷。带队的老师和自学的同学都可以按下面的顺序拆。2. 基础单选不是背概念把变量名、二进制、表达式和循环映射成C检查表基础单选看着零散实际可以归到四张检查表词法检查、数值转换、表达式求值、控制结构。选题时不要凭“眼熟”选先判断题面在考哪张表再用表里的规则逐项排除。这样做的理由很直接校级预选赛的单选题干短选项里常放一个很像正确答案的干扰项比如把关键字当变量名、把字符常量写成双引号、把while说成只能做不确定次数循环。逐项排除比凭语感稳。2.1 变量名与赋值用“三看一跑”筛掉非法写法变量名题先看首字符再看字符集最后看关键字。合法标识符的首字符只能是字母或下划线后续字符可以是字母、数字、下划线大小写敏感不能和C关键字重名。题面里出现int、for、while、return这类词不管它看起来多像英文单词都先标成非法。赋值题则看左值能不能改、类型能不能接、语句有没有分号。字符常量用单引号字符串字面量用双引号char变量接双引号字符串是典型翻车点。检查项题面信号排除动作首字符以数字开头直接判非法字符集出现-、、空格直接判非法关键字int、for、class直接判非法赋值左值常量、表达式在等号左边判非法字符/字符串A与A混用看变量类型再判考场里不要用编译器去试非法变量名编译报错信息对新手不友好还浪费时间。我一般让学生把选项先改写成声明语句比如把选项写成int 名称;再看能不能读通。赋值题也一样先把选项补成完整语句再看分号和引号。这个动作看起来笨但比盯着选项猜稳。提示变量名题先排关键字再排首字符最后排字符集顺序反了容易漏掉关键字。2.2 二进制、表达式与排序比较次数手算表加小样本验证二进制转十进制按权展开从右往左第0位开始乘2的幂。题面给的是二进制数时不要先转成十六进制再绕回来直接列权值表最快。表达式题先看运算符优先级再看整数除法和取模最后看逻辑短路。关系表达式的结果是逻辑值赋值表达式也有结果字符型变量可以参加算术运算因为字符在底层按编码值参与计算。排序比较次数题要先问题面有没有指定排序算法没有指定时不能直接套一个公式得看选项对应的模型。def bin_to_dec(s): v 0 for ch in s: # 从左到右扫描二进制串 v v * 2 int(ch) return v print(bin_to_dec(1011)) # 示例实际考试替换成题面数字这段代码的逻辑是“每读一位把已有结果乘2再加当前位”适合手算后做校验。参数s只接受由0和1组成的字符串题面里如果有前导零也不影响结果。考试时不必写代码重点是知道按权展开和这个循环等价算完可以用小样本反推。排序比较次数更容易错在“最坏情况”四个字。冒泡排序、选择排序、插入排序在最坏情况下都常出现n(n-1)/2这个量级但题面如果给的是具体序列就要按算法实际比较次数数。下面这个函数只用于验证冒泡排序在某个序列上的比较次数不用于直接背答案。def bubble_cmp(a): a a[:] # 不修改原数组 c 0 for i in range(len(a) - 1): for j in range(len(a) - 1 - i): c 1 # 每进入一次内层循环就记一次比较 if a[j] a[j 1]: a[j], a[j 1] a[j 1], a[j] return c参数a是待排序列表返回值是比较次数。题面如果问“最坏情况下需要多少次比较”就把a换成逆序序列如果问“给定序列需要多少次”就按原序列跑。注意不同排序算法的比较次数不同选项里常把冒泡和选择的次数混在一起。表达式题还可以用一个小表检查优先级括号最高其次单目再乘除取模再加减再关系再逻辑与再逻辑或最后赋值。遇到abcd这种混合表达式先算bc再算d最后把逻辑值赋给a。如果题面选项里出现“赋值表达式没有结果”直接排除。2.3 函数、循环与二维数组先画内存/状态表再选答案函数题常考主函数唯一、程序入口、递归自调用、函数嵌套定义。C里主函数是程序执行入口一个程序有且只有一个主函数递归函数是函数自己调用自己但不是“所有函数都可以自己调用自己”这种绝对说法递归要有终止条件。函数不支持在函数内部再定义函数这是标准C的常规限制lambda是另一回事题面一般不会把两者混在一起考。循环题先区分“确定次数”和“不确定次数”。for常用来做确定次数循环while既能做确定次数也能做不确定次数不能说while专用于不确定次数。break跳出当前循环continue跳过本次循环后面的语句。题面里如果出现while(1)配break要重点看break在哪个条件分支里。二维数组题先按行优先展开。题面给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]。这种题不要凭行列直觉猜先在草稿上画三行两列的小表把初值按顺序填进去。表达式值说明a[0][0]2第一行第一列a[0][1]3第一行第二列a[1][0]4第二行第一列a[1][1]5第二行第二列a[2][0]6第三行第一列a[2][1]7第三行第二列注意二维数组初始化按行优先填充不要按列去数否则整道题会连环错。3. 程序阅读题怎么复现七段C代码的变量快照与边界推演程序阅读题是这份试题里最值得先做的部分因为它能直接暴露“看代码跳步”的习惯。题面给出七段左右的C代码每段都不长但循环边界、break位置、变量初值、函数返回值这几个点只要错一个选项就会偏。我一般要求先不选答案按“输入样例→变量快照→输出”走一遍再用机器跑一次对齐。程序阅读不是靠背代码而是靠可复现的推演过程。3.1 约数计数与公因子个数从for边界到break时机第一段程序用for(i1;in;i)统计n%i0的次数输出的是n的真因子个数不包含n本身。以n12为例i取1、2、3、4、6时整除cnt5。如果题面输入的是别的数按同样方式列i和cnt两列不要心算跳步。这段代码的边界是in不是in所以n本身不会被计入。第二段程序同时看m%i0和n%i0统计公因子个数并且有if(cnt6) break;。这里的关键是cnt先加再判断break只影响当前循环。手算时按i从小到大列三列i、是否整除、cnt。如果cnt在第6次才触发break后面的i不再看。很多错项就是把break当成“跳过本次”实际它是直接结束循环。#include bits/stdc.h using namespace std; int main() { int n 12, m 18, cnt 0; for (int i 1; i n; i) { if (m % i 0 n % i 0) cnt; if (cnt 6) break; // 第6个公因子出现后立即退出 } cout cnt endl; // 本例输出4因为公因子只有1,2,3,6 return 0; }这段代码用于验证手算参数n、m换成题面输入即可。逻辑说明先判断公因子再累加然后检查是否需要提前退出。注意本例不会触发break因为公因子不到6个如果题面数据能凑到6个就要在快照表里标出退出位置。第三段程序先求a和b的最小值再从大到小找公因子找到后break最后输出a*b/d。这实际是先求最大公因子再算最小公倍数。手算时先写d的候选值从min(a,b)往下试第一个满足两个整除的就是d。最后一步乘法可能超出直觉但按公式走就不会错。3.2 回文、筛法、素数判断把模板题拆成输入-状态-输出三段回文数题用f(x)把数字反转再和原数比较。while(t!0)里每次取t%10接到s后面然后t/10。这段代码的核心变量是s和t手算时对每个i写一行i、反转结果、是否回文。题面统计1..n的回文数个数1到9都是一位数回文后面按位推。筛法题先看a[1]1再看if(a[i]!0) continue;然后标记倍数。数组a[i]的语义不是“素数标记”而是“非素数标记”a[1]1合数被标成1素数保持0。最后a[i]a[i-1](1-a[i])做前缀和统计的是1..n里的素数个数但1被排除。这个语义如果看反输出就会整体偏小或偏大。def prime_prefix(n): a [0] * 10010 a[1] 1 for i in range(2, 10001): if a[i] ! 0: continue for j in range(2, 10000 // i 1): a[i * j] 1 for i in range(1, n 1): a[i] a[i - 1] (1 - a[i]) return a[n] print(prime_prefix(10)) # 10以内素数个数4参数n是题面输入上界返回值是素数个数。代码里a[1]1是理解整段程序的关键1-a[i]在素数位置得1在合数和1的位置得0。手算时先打印前20个a[i]看语义是否符合“合数标1”再算前缀和。素数判断题用for(i2;i*ix;i)如果中途整除返回0否则返回1。主程序先判n是否素数是则输出1否则如果n是偶数输出2否则如果n-2是素数输出2否则输出3。这段程序的分支顺序不能乱先判素数再判偶数再判n-2。手算时把n代进去按分支逐层走不要跳到最后。3.3 用测试输入对齐手算与机器结果编译、运行、比对程序阅读题最稳的复现方式是编译原代码用题面输入跑一遍。考场不能编译时就在草稿上按行写变量快照平时训练一定要跑机器因为机器的输出不会骗人。下面是一套通用命令把题面代码保存成read1.cpp后编译运行。g -O2 -stdc17 read1.cpp -o read1 ./read1第一行是编译-O2开优化-stdc17指定常用标准第二行运行。输入按题面给比如第一段程序输入12输出应为5。如果手算和机器不一致先查循环边界再查变量初值最后查break和continue的位置。这个顺序比盯着代码反复看有效。提示程序阅读题的手算表至少写三列循环变量、关键条件、累计变量。只写答案不写过程错题第二次还会错。以第七段递归求最大公因子为例f(a,b)在b0时返回a否则返回f(b,a%b)。输入12 18调用链是f(12,18)→f(18,12)→f(12,6)→f(6,0)返回6。手算时把每次调用的两个参数写出来递归题就不会乱。第八段程序从i2开始递增跳过所有7的倍数统计i的真因子个数找到第一个真因子个数为6的7的倍数就输出。这段代码的cnt统计的是j2到i-1的整除次数不含1和自身。手算时先列7的倍数再列每个数的真因子找到第一个满足条件的就停。题面选项如果给的是“因子个数”而不是“真因子个数”就是典型干扰。4. 问题阅读题落地手机菜单、服务器压缩、骰子、爬山四类建模问题阅读题看起来像阅读理解实际考的是建模把长题干里的对象、状态、操作、约束抽成变量和更新规则。四类题分别对应模拟、事件调度、可行域判断、差分约束。做这类题不要先读选项先把题干里的“编号”“位置”“时间”“面数”“海拔”标出来再决定用数组还是用公式。4.1 手机菜单编号和位置分离维护pos与screen手机菜单题最容易错在把应用编号当位置。题干里明确说“注意区分应用程序的编号以及位置”这句话就是提醒。建模时用两个数组pos[app]存应用app当前在菜单中的位置at[p]存位置p上是哪个应用。屏幕号由位置算出来位置从1开始每屏k个图标屏幕号是(p-1)/k1。初始当前屏幕是1启动一个应用前先算目标屏幕滚动次数是两屏幕号差的绝对值再加一次双击操作。int screen_of(int p, int k) { return (p - 1) / k 1; // 位置p所在屏幕号位置从1开始 } // 启动应用x的核心更新pos和at同步交换 int p pos[x]; int q p - 1; // 前一个位置 if (q 1) { int y at[q]; swap(pos[x], pos[y]); swap(at[p], at[q]); }这段框架说明两件事屏幕号只由位置算不由应用编号算交换时pos和at必须同时更新。参数p是应用当前位置q是前一个位置q1时不做交换。题干说“已经处于第一个位置时图标位置不变”对应q1的判断。手算时按计划启动序列逐个更新每步记录当前屏幕、目标屏幕、滚动次数和交换后的pos最后累加。注意手机菜单题不要只维护一个pos数组就完事交换时还要能通过位置找到应用否则下一步会拿错编号。4.2 服务器压缩按完成时间建事件队列不按编号拍脑袋服务器压缩题的关键是时间单位。题干说每个服务器每秒可以压缩1分钟时长的视频视频长度以分钟给出所以压缩耗时要把分钟换算成秒。多个服务器可以并行同一个视频只能在一个服务器上压缩视频按上传时间先后排队有服务器空闲就立即开始。建模时用优先队列存每个服务器的空闲时间按视频上传顺序处理。变量含义更新方式freeTime[i]第i个服务器下一次空闲时刻取最早空闲服务器start视频开始压缩时刻max(上传时刻, freeTime)finish视频完成时刻start 长度换算秒数处理每个视频时从优先队列取出最早空闲的服务器开始时间取“上传时间”和“服务器空闲时间”的较大值完成时间等于开始时间加压缩耗时再把该服务器的新的空闲时间压回队列。这样不用按视频编号猜也不会把并行服务器当成串行。题面里第一个和最后一个视频长度不同正好用来检查有没有把长度写死。priority_queuelong long, vectorlong long, greaterlong long pq; for (int i 0; i n; i) pq.push(0); // n个服务器初始空闲 for (int i 0; i m; i) { long long t upload[i]; // 上传时刻 long long need len[i] * 60; // 长度分钟换算成秒 long long free pq.top(); pq.pop(); long long start max(t, free); long long finish start need; pq.push(finish); ans[i] finish; }参数说明n是服务器数m是视频数upload[i]是上传时刻len[i]是视频长度分钟数。代码里len[i]*60是单位换算如果题面长度单位不同就按题面改。逻辑说明优先队列保证每次取最早空闲服务器max保证视频不会在服务器空闲前开始。手算时按时间轴画甘特图比按编号列式子直观。4.3 骰子与爬山可行域、差值约束和极值反推骰子题给若干个骰子每个骰子有不同面数面上数字从1到面数掷出数字之和为S判断哪些数字可能出现。不要用平均数猜直接用可行域如果第i个骰子取x其余骰子的和必须在“其余骰子最小和”和“其余骰子最大和”之间。最小和是每个骰子取1最大和是每个骰子取自己的面数。剩余和落在区间内这个x才可能。爬山题给总天数、首尾海拔、相邻两天海拔差不超过D求可能到过的最高海拔。做法是正向推上界再反向推上界。正向h[i] h[1](i-1)*D反向h[i] h[N](N-i)*D。第i天可能达到的最高值取两个上界的较小值再对所有天取最大。这个公式只用首尾和差值约束不需要枚举所有海拔。def max_height(n, h1, hn, d): best 0 for i in range(1, n 1): up h1 (i - 1) * d # 从第1天正向推 down hn (n - i) * d # 从第n天反向推 best max(best, min(up, down)) return best参数n是天数h1是第1天海拔hn是第n天海拔d是相邻两天最大差。返回值是可能到过的最高海拔。逻辑说明正向和反向都给上界真实海拔不能超过两个上界中的较小者。如果题面首尾海拔与d不兼容这个模型还要先判无解但校级预选赛通常给合法数据。提示骰子题先算其余骰子的最小和、最大和爬山题先写正向、反向上界两个模板都能在草稿上直接列。5. 避坑与排查校级预选赛刷题最容易翻车的五处这份试题的坑不在难题而在“看起来会”的地方。基础单选考的是规则边界程序阅读考的是状态跟踪问题阅读考的是建模对象。下面五条是带练时最常见的翻车记录每条按“现象→原因→解决”写照着排查能省不少后悔药。5.1 五个高频翻车点现象、原因、解决踩坑一变量名题把关键字当合法。现象是选项里出现for、int、while觉得“字母开头、没有符号”就选了。原因是只记了首字符规则没把关键字表过一遍。解决是把C关键字抄成一张小表做题时先扫选项里有没有这些词有就划掉再看首字符和字符集。踩坑二赋值题把双引号字符串塞给char。现象是char c A;被当成正确写法。原因是把字符常量和字符串字面量混了。解决是看到单引号才想字符看到双引号先想字符串char变量接单引号字符字符串要用字符数组或string。题面里如果有 和 先看左值类型再判。踩坑三程序阅读题忽略break位置。现象是公因子个数题多算了好几轮。原因是break写在cnt之后计数先发生再退出。解决是按行写快照表列i、条件是否成立、cnt当前值看到break就在那一行画终止线。不要用眼睛扫循环眼睛最容易跳过break。踩坑四筛法题把a[i]0当合数。现象是素数个数统计偏小。原因是没注意a[1]1且合数被标成1素数保持0最后用1-a[i]做前缀和。解决是先打印前20个a[i]确认“1代表非素数、0代表素数”的语义再算前缀和。语义看反后面全错。踩坑五手机菜单题把应用编号当位置。现象是滚动次数算出来和选项对不上。原因是pos数组存的是位置但交换时只更新了应用编号没更新位置到应用的映射。解决是同时维护pos[app]和at[position]交换时两个数组一起换每次启动前用pos[x]算屏幕号不要用x直接算。踩坑六服务器压缩题分钟和秒混用。现象是完成时间相差60倍。原因是题干说“每秒压缩1分钟时长”视频长度给的是分钟代码里直接拿分钟当秒加。解决是统一单位长度先乘60换成秒最后输出再按题面要求换算。手算时在草稿上标单位别只写数字。5.2 一套10分钟自检流程从题面到答案做完一道题后不要立刻对答案先走一遍10分钟自检。第一步回读题干里的限制词比如“最坏情况”“不包含”“已经处于第一个位置”“每秒压缩1分钟”。第二步把关键变量列成表程序阅读列循环变量和累计变量问题阅读列对象和状态。第三步用一个小输入手算和选项对照。第四步检查单位、边界、初值、break位置。第五步如果时间允许把程序阅读题的关键片段抄出来编译跑一次。自检项问自己什么常见错误边界循环是还是真因子算进自身初值累计变量从0还是1开始筛法a[1]看反分支break在累加前还是后公因子多算单位分钟、秒有没有统一完成时间差60倍对象编号和位置有没有分开手机菜单滚动次数错注意自检不是重做一遍而是针对易错点做定点检查。时间紧时优先查边界、初值和单位。6. 最后一周的限时诊断用这份试题PDF做错题到模板的闭环最后一周不要再按题型从头刷用这份试题PDF做一次限时诊断更有效。我的做法是分三段30分钟做程序阅读20分钟做问题阅读15分钟做基础单选中间不查资料。程序阅读重点看手算表能不能和机器输出对上问题阅读重点看建模变量有没有漏基础单选重点看关键字、字符常量、循环边界这些硬规则。限时结束后不急着看总分先给错题打标签语法规则、状态跟踪、单位换算、建模对象、边界条件。错题标签回看位置补练动作语法规则第2章检查表抄关键字表和字符/字符串规则状态跟踪第3章变量快照重做公因子、筛法、递归三题单位换算第4章服务器压缩手画时间轴标分钟和秒建模对象第4章手机菜单重写pos和at交换边界条件第5章自检表每題做完查、、初值第二遍只做错题要求手算表和机器结果一致问题阅读要能用自己的话复述变量更新规则。第三遍把错题对应的模板写成半页纸比如“筛法先打印前20个标记”“手机菜单先算屏幕号再交换”“服务器压缩先统一秒”。考前一天不再开新题只看这几页模板和易错点。血泪经验是程序阅读题只要手算跳步第二次还会错同一个位置把快照表写完整比多刷十道题管用。从那以后我每次带人做这套题都先让他用30分钟做完程序阅读再把错题按模板归类希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站