资讯动态

少儿信息学竞赛复赛真题解析:循环、前缀和与模拟题高分攻略

发布时间:2026/10/17 13:24:51 来源:尧图企业网站定制
简介这份docx试题来自第18届绍兴市少儿信息学竞赛复赛专为小学阶段编程学习者、信息学入门选手及指导教师准备文档完整收录复赛4道题目好朋友、统计人口、卫星、粉刷匠覆盖变量与数据类型、控制结构、数组与链表、循环结构及基础算法设计等核心考点可作为NOIP、市赛前的模拟演练素材。整份资源仅含1个docx文件容量约32KB内容集中、便于下载打印和对照练习目前已有813人浏览学习是少儿信息学竞赛方向较受关注的真题资料。试题按复赛真实要求编排强调文件名、输入输出格式等规范有助于养成良好参赛习惯。读者可结合题目给出的输入输出样例和进阶数据范围体会不同规模数据下的解题策略四道题从模拟计算到统计查询、环状排布设计能有效锻炼读题分析、算法设计与程序实现能力帮助参赛者快速熟悉比赛节奏与常见题型。1. 考点分布150分钟四道题真正拉开差距的是后两题很多家长把少儿信息学竞赛当成“编程培训班结业考”其实从第18届少儿信息学竞赛复赛试题能明显看出这场考试真正在筛的是三件事读题、边界、复杂度。整套卷共四道题好朋友、统计人口、卫星、粉刷匠考试时间150分钟每题10个测试点、每个测试点10分。前两题对标NOIP入门阶段的基础循环与前缀和小学阶段练熟就能稳稳拿满后两题不考高深算法考的是把绕口规则翻译成代码的模拟能力以及逆向统计的数学意识。准备信息学竞赛或编程认证的同学尤其是刚开始冲NOIP的小学、初中生按这份拆解逐题吃透比盲目刷题库更能抓分。2. 高频考点好朋友——循环、条件判断与“最近可买”的距离2.1 题目在考什么不是排序而是两条规则的交叉筛选“好朋友”是第一道题也是最容易被低估的送分题。房子编号1到n相邻房子距离10米小A住在x号每个房子有一个价格PiPi0表示不可卖小B手里有m元要在距离小A最近的前提下买到一套预算内的房子。输出的是最近距离单位是米不是房号。很多新手第一反应是“找价格最低的房子”这恰恰中了出题人的圈套。题面说的是“在两家距离最近的前提下”也就是说距离的优先级高于价格。正确读法是先在所有能买的房子里也就是Pi不等于0且Pi≤m的房子中把距离小A家最近的找出来输出它和小A家的距离。n最大只有100根本不需要排序一次循环就能解决。考场拿分的关键是三重过滤排除小A自家排除Pi0的不可卖房排除超过m元的房子。三个条件少一个样例可能侥幸通过极端数据就会翻车。2.2 参考实现单层循环维护最小距离#include stdio.h #include stdlib.h int p[105]; // 房子价格下标从1开始 int main() { freopen(friend.in, r, stdin); freopen(friend.out, w, stdout); int n, x, m; scanf(%d%d%d, n, x, m); // 第一行是 n x m不是 n m x for (int i 1; i n; i) { scanf(%d, p[i]); } int ans 1 30; // 距离上限先设一个足够大的数 for (int i 1; i n; i) { if (i x) continue; // 小A自家不可买 if (p[i] 0) continue; // 0 表示不可卖 if (p[i] m) continue; // 超出预算 int d abs(i - x) * 10; // 相邻房距离10米 if (d ans) ans d; } printf(%d\n, ans); return 0; }逻辑很直白一边读一边存价格然后从头到尾扫描凡是命中任意一条过滤规则就直接跳过。保存距离时乘10因为题目规定任意相邻房子的距离都是10米不乘10的话样例输出会从20变成2一测就露馅。几个参数要注意。n表示总房数x是小A的房号m是资金上限读入顺序是“n x m”和很多题目习惯的“n m k”不一样读错一个位置整道题报废。ans的初值用130保证比任何可能的距离都大否则当所有可买房的真实距离都很大时ans可能留在0。n≤100数组开105足够但千万不要因为数据范围小就省掉过滤条件。2.3 三处常见误用与一个考场变式误用一把“不可卖”当成“0元房”。Pi0表示该房不可卖不是免费送。如果看到样例1里0出现在第二个位置误以为2号房免费就会把它纳入备选输出错误距离。误用二先找最便宜再找最近。题目要求“距离最近的前提下”不是“预算内最便宜”。比如预算内最便宜的房子在100米外而30米处有一套房也在预算内正确答案是30米而不是那套便宜房。这类题的最优策略就是遍历取最小距离不需要比较价格大小只要价格不超过m就纳入候选。误用三把“最近”理解成别的形式或者输出房号。输出要求是距离样例给出的20代表两套房隔了2个房号、距离20米。如果输出4号房这个房号格式分直接丢。考场变式如果题目改成“价格优先再考虑距离”就把过滤顺序调换第一步筛价格第二步比距离。时间紧张时建议先按这题的三重过滤写框架再根据题面调整判断顺序。这类基础题拿分的本质不是会写循环而是不踩读题的坑。3. 高频考点统计人口——前缀和是唯一的正解3.1 暴力为什么必超时n和m都到50000每个查询如果重新从a[x]加到a[y]一次就是O(n)总复杂度O(n*m)大约25亿次加法1秒绝对跑不完。题目把“100%数据”写出来就是提示看到50000这个量级暴力过不了。更关键的是这题有10个测试点每个测试点独立算分。暴力写法能覆盖30%数据的小测试点n≤100、m≤100时毫无压力但一到50%数据n≤1000、m≤10000就开始吃力100%数据必然超时。所以想拿全分必须用前缀和先O(n)预处理再O(1)回答每个查询。这道题的英文名people对应输入文件people.in、输出文件people.out。输入格式是第一行n和m第二行n个数表示每户人口数接下来m行每行两个数x和y表示编号x到y不在家。注意这里说的是“不在家”不是“在家”样例解释里那句“也就是只有编号为3的在家时”是题面笔误实际意思是第3户不在家以输入格式和输出结果为准。3.2 参考实现前缀和与区间和公式#include cstdio const int MAXN 50005; int a[MAXN]; long long s[MAXN]; // s[i] 表示前 i 户的总人口 int main() { freopen(people.in, r, stdin); freopen(people.out, w, stdout); int n, m; scanf(%d%d, n, m); for (int i 1; i n; i) { scanf(%d, a[i]); s[i] s[i - 1] a[i]; // 边读边建前缀和 } while (m--) { int x, y; scanf(%d%d, x, y); long long lost s[y] - s[x - 1]; // 不在家的人口x 到 y 的区间和 printf(%lld\n, s[n] - lost); // 能核查到的人数 } return 0; }s[i]表示前i户的总人口例如s[3]a[1]a[2]a[3]。区间x到y的人口和用s[y]-s[x-1]计算。之所以是x-1而不是x是因为前缀和数组里s[x-1]恰好是x之前那段的总和减掉它才能把x包含进来。如果写成s[y]-s[x]会把编号x那一户漏掉。答案等于全城总人口s[n]减去不在家的区间人口lost。用样例验证4户分别是3、1、5、6总人口15查询“3 3”表示第3户不在家lost等于5输出10对应第1、2、4户的人口31610完全一致。3.3 scanf、printf与答案范围题目专门提示“输入输出数据比较多建议用scanf、printf”。50000组查询cin和cout在不关闭同步的情况下会明显变慢没必要冒险。用scanf读、printf打稳。答案范围也要注意。题目说“保证输出的所有答案不超231-1范围”也就是int上限附近。n50000如果每户人口数没给上限总和完全可能超过int的21亿所以代码里s和lost都用long long输出用%lld。这样做没有任何坏处还能避开隐式越界导致的负数答案。4. 高分考点卫星的环模拟与粉刷匠的反向覆盖统计4.1 卫星题目拆解间隔数等于上一次接收到的卫星编号卫星这题题意读三遍才能读懂。有n颗卫星排成一个环编号1到n选手要设计它们的环状顺序使得按规则接收时收到的卫星编号正好是1、2、3……n。规则是先接收1号卫星接下来间隔1颗卫星收到2号再接下来间隔2颗收到3号每次间隔的卫星数量等于上一次接收到的卫星编号。题面用n5的例子演示了“1 3 2 5 4”这个排列1号在位置1间隔1颗是3号下一步收到2号接着间隔2颗收到3号。特别注意两点已接收的卫星不计算在间隔数量里绕圈遇到它会直接跳过未接收的卫星可以在一圈里被反复“间隔”到。这两条和约瑟夫问题很相似但又不一样直接套公式反而容易翻车。考场建议先手推n5的样例过程在草稿上把环画出来标出接收顺序再开始写代码。顺序推明白了模拟代码就是翻译题面。4.2 卫星参考实现从上一次接收位置开始数未接收卫星#include cstdio const int MAXN 10005; int ring[MAXN]; // ring[i] 表示环上位置 i 放的卫星编号 bool used[MAXN]; // used[i] 表示位置 i 是否已被接收 int main() { freopen(star.in, r, stdin); freopen(star.out, w, stdout); int n; scanf(%d, n); used[1] true; ring[1] 1; // 先把1号卫星放在位置1 int pos 1; // 上一次接收的卫星在环上的位置 for (int id 2; id n; id) { int step id - 1; // 间隔数 上一次接收到的卫星编号 int cnt 0; while (cnt step) { // 数 step 颗未接收的卫星 pos pos % n 1; if (!used[pos]) cnt; } while (used[pos]) pos pos % n 1; // 再落到下一个未接收位置 ring[pos] id; used[pos] true; } for (int i 1; i n; i) { if (i 1) putchar( ); printf(%d, ring[i]); } puts(); return 0; }模拟的核心是pos指针。每次接收完一颗卫星pos就停在这颗卫星所在位置下一次从pos的下一个位置出发遇到未接收卫星就计数数够step颗之后继续找到下一个未接收的位置那就是当前编号要放的位置。为什么数完step还要再走一步规则是“间隔step颗后轮到下一颗”所以跳过step颗之后下一个未接收卫星才是目标。这个细节最容易写漏写漏的结果是整个环错位。n5时这段代码能推出排列“1 3 2 5 4”和样例一致。n最大10000总步数约为n(n-1)/2也就是5000万次左右C在1秒内可以跑完如果时间再紧可以改用树状数组维护第k个未接收位置对少儿竞赛来说朴素模拟已经够用。4.3 粉刷匠题目拆解正着刷会翻车倒着数才是正解粉刷匠这题表面是模拟刷墙实际是覆盖统计。墙面n行m列小B只有红、蓝两种颜色每次把一整行或一整列刷成一种颜色一共刷k次问最后有多少个格子是蓝色。n、m、k都能到1000000如果按照格子逐个模拟n乘m可能到10的12次方数组都开不下更别说1秒跑完。正确方向是反向处理。最后一次刷墙操作对最终墙面影响最大越早的操作越容易被后面的操作覆盖。从后往前扫操作序列同时维护两个信息某个行是否已经被更晚的行操作覆盖某个列是否已经被更晚的列操作覆盖。当前操作刷的是第y行如果更晚已经有一次行操作刷过这一行那这次行操作产生的颜色会被那次完全盖掉直接忽略如果还没有那这次行操作影响的是“该行中所有没有被更晚列操作覆盖”的格子。倒着刷的另一个好处是不用比较操作时间的先后顺序。反向扫描时更晚的操作已经先被处理rowDone和colDone天然代表了“未来是否还有操作覆盖它”。正着做需要记录每个时间点再比较反向做一步到位。4.4 粉刷匠参考实现反向扫描加两个计数器#include cstdio const int MAXK 1000005; int op[MAXK][3]; // 存下所有操作x表示行列y表示行号或列号z表示颜色 bool rowDone[MAXK]; // rowDone[i] 表示第 i 行已被更晚的行操作覆盖 bool colDone[MAXK]; // colDone[j] 表示第 j 列已被更晚的列操作覆盖 int main() { freopen(paint.in, r, stdin); freopen(paint.out, w, stdout); int n, m, k; scanf(%d%d%d, n, m, k); for (int t 1; t k; t) { scanf(%d%d%d, op[t][0], op[t][1], op[t][2]); } int unRow n, unCol m; // 尚未被更晚行/列操作覆盖的数量 long long ans 0; for (int t k; t 1; t--) { int x op[t][0], y op[t][1], z op[t][2]; if (x 0) { // 刷第 y 行 if (rowDone[y]) continue; // 这行已经被更晚的行操作覆盖本次无效 if (z 1) ans unCol; // 只有未被更晚列覆盖的格子保留蓝色 rowDone[y] true; unRow--; // 可用的行少一行 } else { // 刷第 y 列 if (colDone[y]) continue; if (z 1) ans unRow; colDone[y] true; unCol--; } } printf(%lld\n, ans); return 0; }为什么刷行时加的是unCol而不是m本次刷第y行蓝色只有那些还没有被更晚列操作覆盖的格子才会保留蓝色已经被更晚列操作覆盖的格子颜色由列操作决定不能算在这行的贡献里。同理刷列时加的是unRow。为什么看到rowDone[y]直接continue同方向更晚的行操作会覆盖整行所以本次行操作不会在最终墙面上留下任何格子。注意列操作不会把整行都盖掉所以colDone不影响rowDone的判断两者分开维护。这两个计数器必须同时维护删掉任何一个都会算错。例如样例2先刷第1行蓝再刷第2列红反向处理时红列覆盖的第2列不计入蓝行统计最终答案是1和样例一致。如果正着模拟容易把先刷的蓝误认为全保留算出错误结果。n、m、k都较大答案用long long比较安全避免n*m接近10的12次方时int溢出。5. 易错失分点提交目录、边界盲区与复杂度误判5.1 文件命名与目录结构丢分最冤的一项错在哪源程序随手命名目录名写成中文、少了字母、大小写不对比如把paint文件夹写成pain评测系统根本找不到源文件。为什么错这场比赛提交的是源程序不是编译好的exe。评测要从D盘根目录下按“选手号/题目英文名/源程序”的层级找文件只交源程序测试时以源程序为准。目录结构题面已经给了示例照抄都不会错但很多人把精力全放在写代码上最后两分钟随便拖了个文件进去。怎么答对开考后在D盘先把四个目录建好英文名严格对应friend、people、star、paint每题写完立刻把源程序放进对应目录文件名同样严格对应比如friend.c或friend.cpp。交卷前留5分钟依次打开四个目录核对文件名再检查freopen里的输入输出文件名有没有写反。这个步骤不需要任何编程能力纯凭习惯就能避开大坑。5.2 输入顺序和输出格式样例能过不代表读对了错在哪好朋友第一行三个数读成n、m、x实际顺序是n、x、m统计人口每题输出一行结果把所有答案打在同一行文件名、文件读写忘写或拼错。为什么错读入顺序错了后面所有判断全部跟着错而且样例未必能暴露。比如n6、x2、m60读成n6、m2、x60程序逻辑看起来能跑输出却完全不是题意要求。输出格式错也是一样答案数字虽然对但评测比对的是整个输出文件多一个空格都可能判错。怎么答对看输入格式说明时把变量名和含义圈出来对照样例手推一遍再写代码。好朋友样例第一行是“6 2 60”一眼就能对上n6、x2、m60统计人口样例输出是两行“6”和“10”说明每个查询必须换行。写完样例后再特意检查freopen里in和out有没有写反。5.3 边界条件小A自家、不可卖房、区间端点错在哪好朋友忘记跳过ix统计人口区间和写成s[y]-s[x]丢掉左端点卫星n取最小值1时数组初始化和输出顺序不对。为什么错边界情况是测试点最喜欢埋数据的位置。x可能等于1也可能等于n区间可能只有一个元素x等于yn可能小到只有1颗卫星。这些情况下常规路径不会出错的代码一旦少一个continue就会算错。怎么答对把数据范围里的最小值代进去手跑一遍。好朋友n2、x1时能买的房子只有2号要确保循环没把1号自家算进去。统计人口查询“3 3”用s[3]-s[2]算出的恰好是第3户人口写成s[3]-s[3]就变成0。卫星n1时直接输出1代码里for循环不进入初始化和输出逻辑也不能崩。5.4 数据范围与答案类型int不够用还不自知错在哪统计人口用int存前缀和粉刷匠用int存答案。为什么错n和m都到50000每户人数没说上限总和可能远超int。粉刷匠更明显n、m各自都能到1000000蓝色格子数可能接近10的12次方int上限只有约21亿。溢出后程序不会报错只会输出一个看起来莫名其妙的大数或负数查半天查不到。怎么答对看到“保证所有答案不超231-1范围”这行字说明出题人自己都在提醒答案靠近int上限直接用long long。粉刷匠在计算n*m的过程中就已经超int答案更是非long long不可。养成习惯涉及累加、相乘、求和一律用64位整数不会吃亏。5.5 复杂度误判能跑样例只是开始错在哪统计人口每次查询重新算区间和粉刷匠开n乘m数组或者逐格更新卫星每次从头数step颗卫星还嵌套多层循环。为什么错样例的数据量小暴力写法跑起来飞快看起来完全没问题。但评测跑的是极限数据统计人口50000乘50000等于25亿次操作粉刷匠的n乘m可能到10的12次方暴力根本不可能在时限内完成。只盯着样例而不看数据范围是少儿竞赛最常见的失分原因。怎么答对拿到题先看“数据范围约定”那一行估算最坏复杂度。统计人口看到50000直接写前缀和粉刷匠看到1000000走反向扫描加计数器卫星n10000时朴素模拟总共约5000万步C可以接受但循环里不要塞重操作比如每次都清空数组或者调用慢函数。把复杂度算在前比代码写得优美更重要。6. 冲刺答题技巧拿分顺序、对拍习惯与五分钟自查清单这套卷子拿分要讲顺序不是从第1题做到第4题。我的习惯是先写好朋友和统计人口这两题逻辑简单、边界清晰闭着眼也能把基础分拿到然后攻卫星它难在读题读懂规则后代码量并不大粉刷匠放最后如果思路卡住优先保前面三题的全分再用剩余时间写粉刷匠的小数据暴力版能拿几个测试点算几个。具体的时间分配可以这样卡前15分钟只读题把四道题的输入输出和样例各自手推一遍特别是卫星这种绕口规则草稿上画一遍胜过读十遍接下来60分钟写前两题写完立刻用样例自测再自己构造两个边界数据中间40分钟给卫星重点检查模拟时pos指针的移动对不对最后留20分钟给粉刷匠和检查提交。对拍是性价比最高的自查方法。没有标准答案不要紧自己写一个绝对暴力的版本生成随机小数据分别跑暴力版和高效版比对输出是否一致。好朋友可以随机生成n在10以内、价格含0的用例统计人口可以随机生成小数组和区间查询卫星可以固定n5和n13验证能否推出样例输出。暴力版和正解输出一致基本可以放心交。交卷前最后5分钟按这个清单逐项过一遍四个输入文件名是不是friend.in、people.in、star.in、paint.in四个输出文件名是不是friend.out、people.out、star.out、paint.out每个源程序是不是放在对应英文名的子目录里freopen里的参数顺序有没有颠倒所有答案是不是用了long long统计人口每个查询是不是单独一行。清单很短但每一条都是真实发生过的翻车点。后来我每次带学生模拟这套卷都会强制在最后5分钟把“目录名-文件名-读入读出-答案类型”走一遍这个习惯救过我好几次也希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑