
简介2024年海淀区中小学生信息学竞赛校级预选赛试题面向海淀区参赛中小学生及指导教师用于赛前自测、校内选拔和考点梳理内容紧扣区级预选赛的命题要求。资源为1个PDF文档资源包仅422KB卷面完整适合直接打印作答或电子屏幕阅读。试卷分为编程基础知识单选与程序阅读单选两部分编程基础题围绕合法变量名、赋值语句写法、二进制与十进制转换、表达式与逻辑判断、函数定义与递归、运算符、循环及break/continue使用、数组等展开程序阅读题则通过求因数个数、公约数与最小公倍数、回文数判断、素数筛选等经典案例要求考生根据给定代码推断输出结果或特定变量值全面考查代码跟踪能力和算法理解水平。已有575人学习浏览学生借助本卷可系统检验C基础掌握情况教师也可快速掌握学情进行针对性讲评与拓展训练。1. 拿到2024年海淀区中小学生信息学竞赛校级预选赛试题先别慌它的套路比想象中固定2024年海淀区中小学生信息学竞赛校级预选赛试题1103.pdf如果你正在对着这份卷子备赛说明你站到了区级信息学选拔的入口上。校级预选赛的定位不是选天才而是筛态度和基本功题目难度不高但考察点很固定C基础语法熟练度、模拟题的拆解能力、数学模板的掌握程度这三样决定了你能不能从预选赛里走出来。许多零基础同学把这卷子当成黑匣子其实它最常出现的题型就三类——模拟、数学、数组字符串提前把它们练透及格线基本到手。接下来的内容我会按“题型识别 → 备考节奏 → 踩坑排查 → 临场流程”四段展开。新手可以跟着从第一道模板题写起已经会写基础程序的同学可以直接跳到避坑章对照检查。读完之后你应该能回答三个问题这份卷子到底在考什么每天该练什么交卷前有哪些动作是白给的。2. 校级预选赛的三大题型拆解模拟、数学、数组字符串怎么学才算到位信息学竞赛的区级预选赛出题人有很强的一致性题目数量通常控制在四到六道分值由易到难排列第一道题基本是送分模拟最后一道题会掺进数组和排序。这和市级、省级比赛那种“考思维爆发力”的风格不同预选赛更像是在问一个问题你有没有把基础语法练到不用想就能写对的程度。所以我不建议在这个阶段去学什么线段树、动态规划、图论算法那些东西对预选赛来说属于高射炮打蚊子。真正值得投入时间的是三类题型的固定套路。2.1 模拟类题型读题三步法先把边界变量单独拉出来模拟题是预选赛里出现率最高的题型也是新手失分最多的地方。它的特征很直观题目描述会把规则讲得明明白白比如“从某个位置开始每天前进多少格”“某年某月某日是星期几”“给一个字符串做循环移位”你只需要把规则原样翻译成循环和判断就能拿到分。听起来不难但实际考场上很多人输在漏看条件。常见的备考误区是拿到题直接上手写循环写到一半才发现边界条件没处理于是开始打补丁补到最后代码变成一团乱麻。我一般会让学生先做三步第一步把输入的数据范围圈出来第二步把所有会变化的边界写成短列表比如行数、列跨度、起始和结束位置第三步再动手写代码。图形打印题是最典型的模拟题也是每年预选赛都绕不开的考点。#include iostream using namespace std; int main() { int n; cin n; for (int i 1; i n; i) { // 第 i 行先输出 n-i 个空格 for (int j 1; j n - i; j) cout ; // 再输出 2*i-1 个星号 for (int j 1; j 2 * i - 1; j) cout *; cout \n; } return 0; }这段代码的逻辑很直白外层循环控制行数内层第一个循环控制空格第二个循环控制星号。关键在 i 与行号的对应关系上如果你能把 n5 时每一行的空格数和星号数先在草稿纸上列出来再回头对照代码循环边界基本不会错。如果两分钟内写不出这段代码说明循环控制还不够熟建议先把行数、空格数、星号数三层关系练到条件反射。预选赛里的模拟题比这个绕的地方在于它常把二维数组和操作组合在一起比如矩阵翻转、蛇形填数这类题的核心还是边界变量要提前算好不能写一步试一步。2.2 数学类题型质数、最大公约数与取模模板数学题在预选赛里的占比通常在两到三成而且规律性极强。翻来覆去就是质数判断、最大公约数、最小公倍数、取模运算这几类偶尔会套一个递推数列的外壳但内核仍然是你背过的模板。数学题对程序运行时间的敏感度很高如果不懂复杂度很容易写一个能过样例却在大数据上超时的版本。质数判断是最常见的送分题核心是枚举到根号 n 就停不需要从 2 试到 n 本身。#include iostream using namespace std; bool isPrime(int x) { if (x 2) return false; for (int i 2; i * i x; i) { if (x % i 0) return false; } return true; } int main() { int n; cin n; cout (isPrime(n) ? Yes : No) \n; return 0; }这段代码要注意两个细节一是 x 小于 2 的情况要单独返回 false二是循环条件用i * i x而不是i sqrt(x)后者每次循环都要重新算一次浮点开方在预选赛数据量下虽然差别不大但坏习惯最好从一开始就别养成。如果数据范围很大还要考虑用埃氏筛一次性筛出区间内所有质数。取模类题目是另一个高频点常见考法是给出一个递推公式让求第 n 项模某个数。这类题的陷阱在于计算过程中间值可能溢出新手往往只对最终结果取模忽略了乘法中间步骤。#include iostream using namespace std; int main() { long long a, b, mod; cin a b mod; long long ans 1; while (b 0) { if (b % 2 1) ans ans * a % mod; a a * a % mod; b / 2; } cout ans \n; return 0; }这是快速幂的模板用来求 a 的 b 次方模 mod。核心思想是把指数拆成二进制每次对底数平方只在当前二进制位为 1 时乘进答案。你不需要完全理解它的数学证明但要记住两个使用场景指数 b 特别大或者中间乘法会超过 long long 范围。预选赛里只要看到“结果对 1000000007 取模”这种描述基本就是在暗示你用这类模板。数学题拿分的捷径是整理错题本不是刷题量。把见过的公式和模板抄在一张纸上考前半小时过一遍比临时翻书管用得多。2.3 数组与字符串题型前缀和、排序和二分数组和字符串题是预选赛的压轴地带难度比前两类高一个台阶但题型也是固定的。这里最常考的是三件事前缀和、排序、二分查找。它们经常组合出现比如先排序再对每个询问做二分或者先算前缀和再快速回答多个区间求和问题。前缀和的代码极短但它解决的是“多次询问区间和”这类高频问题如果你不知道这个套路会写一个每次询问都重新遍历的暴力程序数据一变大就超时。#include iostream using namespace std; long long a[100005], pre[100005]; int main() { int n, m; cin n; for (int i 1; i n; i) { cin a[i]; pre[i] pre[i - 1] a[i]; } cin m; while (m--) { int l, r; cin l r; cout pre[r] - pre[l - 1] \n; } return 0; }这段代码里最容易忽略的是pre[i] pre[i - 1] a[i]这一句它把前 i 项的和存下来之后任意区间 [l, r] 的和就是pre[r] - pre[l - 1]。我故意把数组类型写成了 long long因为如果 n 超过十万、a[i] 再大一些区间和很容易超过 int 的 21 亿上限这是预选赛最经典的爆零点之一。排序加二分的组合题主要考察sort和lower_bound的配合。常见考法是给你 n 个数字然后来 m 个询问每个询问问某个值是否存在或者第一个大于等于它的位置在哪。直接用排序加二分能把复杂度压到 O((nm)logn)而暴力做法是 O(nm)在 n 和 m 都过万时运行时间会从毫秒级变成几十秒。数组和字符串题拿高分的另一个关键是做题时要对下标敏感。预选赛经常出“下标从 1 开始”的题因为这样写前缀和和差分更直观。如果你习惯下标从 0 开始写前缀和时要么统一改掉要么在草稿上画清楚对应关系这种一差之错往往要排查很久。3. 从零基础到预选赛过关8周备考节奏与一次性写对的检查链确定要参加预选赛后最怕的不是能力不够而是时间安排混乱。很多同学今天学两小时排序明天又去刷字符串后天发现语法全忘了回头重新补到头来每样都只学了半桶水。我给备考者推荐的节奏是八周前四周只练语法和基础中间两周过模拟和数学题最后两周进入套题和模拟考状态。这个节奏的核心原则是“先练到不用想再练难题”。预选赛考场上每一分钟都宝贵如果连 for 嵌套循环都要现场想怎么写那后面的大题一定来不及。3.1 8周时间线C语法要练到哪个程度再刷题我用一张表把每周的重点列出来你可以直接照着安排周数学习重点达标标准第1周变量类型、cin/cout、if/else能写一个根据分数输出等级的程序第2周for循环、while循环、嵌套循环能不查资料写出各种三角形打印第3周一维数组、字符数组、string能写出统计字符串中字母数字个数的程序第4周二维数组、函数封装能实现矩阵转置并封装成函数第5周模拟题专项训练连续做10道模拟题正确率不低于六成第6周素数、gcd、快速幂模板能默写出三个模板并说明适用场景第7周排序、二分、前缀和专项能独立完成“排序二分”的组合题第8周完整套题模拟限时2小时完成一套模拟卷稳定在及格线以上前四周是地基千万别赶。语法没练透就去碰算法后面写出来的代码经常是运行结果和预期不一致又说不清问题出在哪只能瞎试这就是编程里的“玄学调试”。我在教学中反复强调一个标准一个知识点你要做到关着书能写出来才算真正会。C语法的记忆量不大但细节很多比如i和i在表达式里的区别、字符串下标从 0 开始、浮点数不能直接用比较这些坑在前三周暴露得越多越好。3.2 一道模拟题的完整求解流程从读题到写出能提交的代码很多人刷题时习惯读题两分钟然后立刻写代码这是一个坏习惯。我在第 2 章提过读题三步法这里我把完整流程展开用一道数字三角阵的典型题走一遍。题目描述长这样输入正整数 n要求输出 n 行第 i 行输出从 1 开始连续递增的 i 个数相邻数字用空格隔开行末没有多余空格每行结束后换行。先做读题三步输入是一个正整数 n输出是 n 行数字行数是唯一的边界变量当前要输出的数字是另一个状态变量。想清楚这两点代码结构就可以直接搭出来。#include iostream using namespace std; int main() { int n; cin n; int cur 1; for (int i 1; i n; i) { for (int j 1; j i; j) { cout cur; if (j ! i) cout ; } cout \n; } return 0; }这里有一个细节经常被忽略每行行末不能有多余空格。有没有发现我在输出空格时加了if (j ! i)判断只有当当前列不是最后一列时才输出空格这样就保证了行尾没有空格。这种格式化细节在判题系统里往往会变成 Presentation Error虽然不算完全零分但浪费了一次提交机会有时候还会被考场规则扣分。写完代码不要急着提交先用手算验证 n3 时的输出第一行是 1第二行是 2 3第三行是 4 5 6然后和程序输出对比。这一步看似多余实则是防止你把边界算错的最笨也最有效的方法。3.3 本地对拍用暴力程序当裁判验证优化思路不翻车进阶备考者经常遇到一个问题我写了一个自认为高效的解法但不确定它对不对。这时候玄学猜答案不如写一个对拍程序。对拍的意思是写一个效率低但逻辑绝对简单的暴力程序作为标准答案再用随机数据同时跑你的优化程序和暴力程序逐个对比输出。预选赛题目数据范围通常不会太大暴力程序完全能跑出正确答案。对拍能帮你验证优化程序在小数据上是否和暴力结果一致如果不一致说明优化思路在某个边界条件下有问题。#!/bin/bash # 对拍脚本生成随机数据比较两个程序的输出 for i in $(seq 1 1000); do ./gen input.txt ./my_solution input.txt my_out.txt ./brute_force input.txt brute_out.txt if ! diff -q my_out.txt brute_out.txt /dev/null; then echo WA on test $i break fi done echo all tests passed这个脚本做的事情是循环一千次每次先用gen程序生成一组随机输入然后分别运行my_solution和brute_force用diff比较输出。只要有一次不一致就打印WA on test并停止否则打印all tests passed。gen程序是你自己写的随机数据生成器它要保证数据范围覆盖题目的边界值比如 n1、n1000000、数组里有负数等情况。对拍框架本身不复杂但它是备赛过程中最能帮你建立信心的一步。很多翻车场景是“优化程序跑小数据对跑大数据错”对拍就是为了让小数据先替你把所有边界踩一遍。值得注意的是对拍脚本要在本地命令行环境里跑你需要会简单的编译操作比如g gen.cpp -o gen。3.4 定位边界错误先看输入输出格式再用中间变量追踪程序写出来但输出不对第一步不要改代码而是先检查输入输出格式是否和题目要求一致。预选赛里相当一部分“WA”其实是读错了输入比如题目说每组数据用换行分隔你却用了空格。如果格式没错就要在代码里加中间变量的输出把你认为应该在某个阶段出现的值打印出来看一眼。这是最朴素的调试方法但它对新手最友好。#include iostream using namespace std; int main() { int n; cin n; for (int i 1; i n; i) { // 调试语句观察当前行号和累计输出数量的变化 cerr debug: i i , cur cur endl; for (int j 1; j i; j) { cout cur; } cout \n; } return 0; }注意这段代码我用的是cerr而不是cout因为cerr在判题系统里通常不会计入标准输出。本地运行时它会把调试信息打印到终端提交时你删掉这些行也不会影响最终结果。调试语句的作用是让你把程序在每一个关键节点的状态可视化而不是靠肉眼去猜是哪一行出了问题。如果加了调试语句还是找不出问题就把代码放一边在草稿纸上手动跑一遍小数据一步步写出当前变量的值。人脑按顺序执行代码比编译器调试器更直观对小规模数据来说这个方法基本百试百灵。4. 预选赛踩坑记录五条血泪经验让翻车概率降下来这一章是过去几年我看到的考生最容易踩的坑每一条都有真实的翻车案例。这里我按“现象 → 原因 → 解决”的顺序写你可以把它当成一个自查清单。如果你的程序在本地跑起来正常提交却各种报错很可能就落在下面五条里。4.1 int溢出样例全过、提交爆零的典型场景现象本地用样例数据测试结果完全正确但提交到线上评测系统在小数据上也不对或者只有一部分数据对。你反复检查逻辑怎么都想不通。原因你的程序里某个变量的中间值超过了 int 的表示范围。int 在绝大多数环境下是 32 位最大只能表示 2147483647约 21 亿。前缀和、累乘、快速幂这种运算中间值很容易轻轻松松破亿。解决把所有可能参与大数运算的变量都改成long long。不要只在“你觉得会大的地方”改一律改掉更省心。如果涉及取模模数也建议用long long接收。这个错误的隐蔽性在于小数据不会触发你只有被评测系统教育一次才会长记性。4.2 循环复杂度失控1e5 的数据千万别套 O(n^2)现象程序在小数据上运行很快换成实际测试数据后卡得不出结果或者直接运行超时。有些同学以为是电脑太慢其实不是。原因你写了一个 O(n^2) 的双重循环数据规模却高达 10 万。10 万的平方是 100 亿任何普通程序都跑不完。解决写循环嵌套之前先估算一下最大复杂度。预选赛的时限通常在一秒到三秒一个普通 for 循环每秒大概能跑 1 亿次简单操作。如果你算出来总操作次数超过 1 亿就要立刻考虑优化能否用前缀和替代求和循环能否用二分替代线性查找能否用排序加双指针替代双重循环。把复杂度压到 O(nlogn) 是预选赛的核心能力。4.3 cin 和 scanf 混用同步开关背后的一个隐藏状态现象程序里同时用了cin和scanf读输入结果发现有时候读到的值是错的或者程序运行变慢到超时。原因cin和scanf使用不同的缓冲机制混用时可能因为内部同步状态不一致导致读入顺序错乱或者反复刷新缓冲区导致性能下降。解决要么全用cin要么全用scanf不要混。如果用cin在main开头加上两行按我的习惯是ios::sync_with_stdio(false); cin.tie(nullptr);这两行的作用是取消cin与stdio的同步并解除cin与cout的绑定能让输入输出速度明显提升。如果你决定用scanf那就不要再用cin读任何东西。这个坑非常隐蔽因为它不是每次都会出错偶尔“玄学”地工作偶尔又崩溃。4.4 下标从 0 还是从 1 开始一差之差让整道题结果偏移现象程序能运行但输出结果从某一行开始整体偏移了一位。比如题目要求输出第 1 到第 n 项你的程序输出了第 0 到第 n-1 项。原因你写循环时下标习惯从 0 开始但题目里数组和序列是从 1 开始编号的。如果你的代码里数据结构的下标和题目的编号没有对齐后续所有操作都会偏移一位。解决拿到题目先看数据描述的起始编号如果题目说第 1 个元素你最好在代码里也用 1-based。写vector时直接初始化大小为 n1下标从 1 开始用。千万别中途混合使用两种下标习惯那会让代码变成一锅粥。4.5 输出格式行尾空格、最后一行换行这两个扣分点现象程序逻辑完全正确但评测结果提示格式错误。原因多输出了空格或者少输出了最后的换行。有些判题系统对行尾空格敏感有些则只判断换行但你没有必要去赌。解决输出每个元素时判断当前是否最后一个如果不是才输出空格。循环结束后统一输出一个换行。把“最后一项单独处理”这个模版背下来能覆盖绝大多数输出格式要求。注意预选赛的评测环境可能比本地更严格任何格式错误都有可能导致非零分被扣除提交前用样例数据逐字对比输出是一条保命线。5. 考场时间里最该守住的一条线时间分配与交卷前检查清单考试拼的不只是你会不会还有你在有限时间内的稳定性。预选赛通常两小时四到六道题很多同学的时间分配是“第一题磨半小时最后一题只剩五分钟”结果白白把送分题拖到来不及。我给你的建议是把时间切成三段。5.1 两小时考试的时间分配表时间段动作说明开考后 10 分钟通读全部题目只读题不写代码用笔圈出每道题的数据范围接下来 50 分钟从前往后做模拟和数学题先把稳定拿分的题做完做完写稳再留 40 分钟做数组字符串题如果卡住超过 15 分钟先跳过做下一个最后 10 分钟统一检查提交不写新逻辑只检查输出和格式这个方案的核心原则是“先拿分再冲分”。模拟和数学题是你最有把握的先把它们彻底拿稳。数组字符串题如果超过 15 分钟没有进展果断跳过因为后面可能还有更值得的分数。5.2 提交前花三分钟做的五个检查交卷前五分钟不要再去写新题就做五件事第一每道题重新用自己的样例跑一遍确认输出和题目给的结果完全一致包括空格和换行。第二检查文件读写的适用范围预选赛有的题目直接标准输入输出有的要求指定文件名千万别把freopen的路径写错。第三代码里如果有调试用的cerr输出全部删掉或注释掉。第四确认提交的源代码是最终版本不要出现编译器缓存了旧代码的情况。第五把每个输出语句的后半段再读一遍特别是if (j ! i)这种行尾空格判断。考场上最后一个习惯是我自己练习时强迫自己不断养成的不急着提交先把刚写的代码从头到尾读一遍用眼睛执行一次看中间的变量推进是否和你脑中的逻辑一致。很多时候眼睛能发现手写的漏洞。预选赛不是终点它是给你一个“我的基本功到底过关没有”的答案。如果这次没过把做错的题整理成错题本按题型归类下一次你会发现很多看起来不一样的题目其实就是同一个套路换了一层外衣。希望这五章的内容能帮你把这份卷子的套路看清楚也希望你在真正踏上考场的那一刻心里装的不是紧张而是一张清晰的地图。希望帮到你。本文还有配套的精品资源点击获取