news 2026/10/17 4:11:58

编程入门周赛第12周复盘:循环、分支与数组的综合应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
编程入门周赛第12周复盘:循环、分支与数组的综合应用

1. 第12周赛题摸底:这个阶段究竟在考什么

每周日晚上的编程周赛,基本已经成了我带班这几年的固定节目。这周是2025年秋季学期的第12周,语言普及奠基组这一场,我盯着题目列表看了半天,最大的感受是:出题人明显开始“收网”了。前几周还在老老实实考单点语法,这周已经有意把输入输出、循环、分支、数组揉在一起出综合题。对于刚开始学编程的孩子来说,第12周是一个很微妙的节点——基础语法基本讲完,但还没正式进入算法系统训练,这个阶段的赛题考的不是谁懂的知识多,而是谁能把学过的东西组合起来用。

先说清楚“语言普及奠基组”到底是个什么定位。它不是选拔尖子的竞赛组,而是面向刚开始接触编程语言的学生设置的入门级周赛。参加这个组的孩子,通常已经能写顺序结构、理解for和while循环、会用if分支、知道数组怎么存数,但对“算法”两个字还没有成体系的概念。周赛的意义在于每周用5到6道题,把这个阶段该掌握的语言技能点逐一检验一遍。第12周的题目密度和难度,恰好卡在“基础语法复习”和“入门算法启蒙”的中间地带,既没有为难人,又让稍微偷懒的孩子现了原形。

我习惯拿到题目先把所有题扫一遍,再按难度排个序。这周的题大致分成三档:第一档是纯粹的语法题,基本上读完题就能想到怎么写,属于送分题,用来稳定选手心态;第二档是典型的基础应用,需要把两三个知识点串起来,比如循环里面套条件判断,或者数组里面做计数统计,这是全卷的主体,区分度主要在这一段;第三档是压轴题,虽然还是用基础语法就能做,但需要一点建模能力,也就是能把日常问题抽象成代码逻辑,这一档对普及组的孩子来说就是拉开差距的地方。

有一个现象值得单独说一下。很多孩子前几周周赛成绩都不错,一到第12周这种“混合卷”就开始掉链子,原因不是不会写代码,而是不会判断题目的真实意图。比如一道题表面是在讲一堆小朋友排队报数的故事,实际上考的是“取模运算”,或者一道题看起来是字符串处理,本质上是考察数组下标的映射关系。这周的题目在设计上恰恰放大了这个特点,用场景包装把知识点藏得深了一些。对家长和老师来说,第12周的成绩滑坡不是因为孩子退步了,而是因为考核维度变了,这一点要在复盘时跟孩子讲清楚,别一上来就批评。

2. 核心知识点梳理:第12周题目背后的四条主线

2.1 输入输出与格式化陷阱

这一周有几道题对输入输出的考察不是走过场,而是实实在在地埋了坑。最常见的一个坑是:题目给的输入样例里一行有多个整数,但并没有明确说明每行有几个。这种时候如果只用一个cin读固定次数的变量,就会漏读或者多读。正确的思路是循环读入,或者先读行数再读数据。具体到代码上,C++里面对于“第一行给一个整数n,接下来n个整数”这种输入,老练的选手会条件反射地写出类似这样的框架:

#include <iostream> using namespace std; int main() { int n; cin >> n; for (int i = 0; i < n; i++) { int x; cin >> x; // 处理每个读入的 x } return 0; }

这种格式很基础,但第12周的赛题里它出现得非常频繁,因为综合题读入的数据往往不止一组。另外,输出格式也要提醒孩子注意。题目要求“每个结果占一行”,但经常有孩子把所有结果挤在一行输出,这种错误查代码很难发现,因为逻辑没错,就是输出格式不对。我的习惯是让孩子在写代码之前先把输出样例在草稿纸上写一遍,看清楚换行、空格、逗号,再动手敲代码。

2.2 分支逻辑的边界意识

分支语句本身很简单,难的是边界条件的判断。第12周里有一类题是典型的“区间判断”问题:给定一个分数,判断等级,或者给定一个年份,判断是否闰年。这种题几乎每个孩子都会写,但总有一些人在边界值上翻车。比如判断闰年,规则是“能被4整除但不能被100整除,或者能被400整除”,这个规则的顺序非常关键。有的孩子写成了“能被4整除且能被100整除”,直接把正确的年份判错了。

我经常跟学生说,写分支条件的时候要养成列“边界表”的习惯。拿闰年举例,至少要列出2000年(能被400整除)、1900年(能被100整除但不能被400整除)、2024年(能被4整除但不能被100整除)、2023年(不能被4整除)这四类,每一类在代码里跑一遍结果对不对。第12周的题目虽然不难,但几乎每道跟判断有关的题,都能在某个边界值上抓到一批粗心的孩子。这不是细心不细心的问题,而是方法问题——没有边界表,全靠肉眼硬看,检查十遍也发现不了错。

2.3 循环中的“循环不变量”

循环是第12周当之无愧的主角。这周的赛题里至少有四道题是绕着循环展开的,区别只在于循环里面做的事情不同:有的在累加求和,有的在统计个数,有的在寻找最大值最小值。很多初学者写循环全凭感觉,循环变量怎么变、循环什么时候结束,脑子里没有清晰的图景。我教学生时反复强调一个概念——循环不变量:每次循环开始之前,某个变量的状态应该是可描述的,比如“sum存的是前i个数的总和”,这个描述在整个循环过程中保持不变,只是i在往前走。

举个例子,一道很常见的题:读入n个成绩,输出最高分和最低分。初级写法是设置max_score = -1,min_score = 101,然后每读一个分数就更新。这个写法没问题,但孩子要能说清楚为什么初始值要设成-1和101,而不是0和0。如果说不清楚,说明对循环不变量还没有真正理解:初始值必须保证第一个读入的分数一定能更新它,所以最大值要设置成比任何可能的分数都小,最小值要设置成比任何可能的分数都大。第12周里这类题的意义,不是考怎么找最大值,而是考孩子能不能在循环过程中保持逻辑一致。

2.4 数组与计数的经典套路

数组的引入是第12周的一个重要信号。前几周还停留在“存几个数求和”的层面,这周已经开始出现“桶计数”的影子了。所谓桶计数,就是用数组下标代表数值本身,数组里存的是这个数值出现的次数。比如读入n个0到100之间的整数,要统计每个分数段的人数,就可以开一个大小为101的数组cnt,每读入一个数x,就执行cnt[x]++,最后遍历一遍数组就能得到完整分布。

对初学者来说,桶计数最大的认知障碍是“为什么要用数组下标去代表数字”。有一次课堂上我拿乒乓球做类比:假设有100个编号的盒子,每次抽到一个号码牌,就扔进对应编号的盒子里,最后数每个盒子里有多少个号码牌。数组就是那一排盒子,下标就是盒子的编号。第12周的题目中,这种思路出现得不算多,但一旦出现了就是整道题的核心。孩子如果能从这个角度理解数组,后面学排序、学哈希、学图论都要轻松很多。

3. 典型赛题拆解:四道有代表性的题完整复盘

这里面的四道题,是我根据第12周普及奠基组命题规律以及同期多场同类比赛的特征,整理出来的典型样例。不是一字不差的原题,但每一道的考法和坑点都很有代表性。拿到赛卷后,我建议家长不要只盯着分数,而是让孩子对着这几类题逐一复盘,看自己卡在了哪一类上。

3.1 数列分段求和

题面描述:输入一个正整数n,再输入n个整数。把这n个整数分成三段:前三分之一、中间三分之一、后三分之一,分别求出每一段的和。n保证是3的倍数。

这道题表面上是求和,实际上考的是对循环范围和数组下标的掌控。第一段的下标范围是0到n/3 - 1,第二段是n/3到2*n/3 - 1,第三段是2*n/3到n-1。最容易出错的地方在于边界:n/3到底是第一段的结束还是第二段的开始,很多孩子在这里栽跟头。

我的建议是不要硬记公式,而是画一个数轴,标出0、n/3、2*n/3、n这四个点,然后让孩子把循环变量i的每一个取值标在数轴上,看看到底落在哪一段。这种画图的方法在入门阶段非常管用,比讲十遍语法都有效。代码上,可以用三个独立的循环分别求和,也可以一个循环里用if判断每个数属于哪一段:

#include <iostream> using namespace std; int main() { int n; cin >> n; int a[1005]; // 尽量开大一点,避免边界越界 for (int i = 0; i < n; i++) cin >> a[i]; int sum1 = 0, sum2 = 0, sum3 = 0; for (int i = 0; i < n; i++) { if (i < n / 3) sum1 += a[i]; else if (i < 2 * n / 3) sum2 += a[i]; else sum3 += a[i]; } cout << sum1 << " " << sum2 << " " << sum3 << endl; return 0; }

这道题第二种做法用到了分支嵌套在循环里的结构,是第12周最重要的代码模式之一。如果有孩子连题目都读不明白,大概率是“分成三段”这个概念没有转化为“下标区间”的问题。建议回到画数轴的步骤,把抽象概念可视化,不要急于讲代码。

3.2 字符统计与大小写转换

题面描述:输入一行字符串,长度不超过100。统计其中大写字母、小写字母、数字字符分别有多少个。然后把这行字符串中的小写字母全部转换成大写字母输出。

这题在普及组里属于非常经典的“字符串入门三件套”——遍历、判断、转换。C++里处理字符串要用#include <string>,然后可以用getline(cin, s)读入一整行,用s.length()或者s.size()获取长度,用s[i]访问每一个字符。

字符判断的关键是ASCII码的连续性:大写字母’A’到’Z’的ASCII码是连续的,小写字母’a’到’z’也是连续的,数字字符’0’到’9’同样连续。所以判断一个字符ch是不是大写字母,只需要写ch >= 'A' && ch <= 'Z',不需要把26个字母都枚举一遍。大小写转换就更简单了,小写字母转大写是ch - 32或者ch - 'a' + 'A'。

#include <iostream> #include <string> using namespace std; int main() { string s; getline(cin, s); int upper = 0, lower = 0, digit = 0; for (int i = 0; i < (int)s.length(); i++) { char ch = s[i]; if (ch >= 'A' && ch <= 'Z') upper++; else if (ch >= 'a' && ch <= 'z') lower++; else if (ch >= '0' && ch <= '9') digit++; } cout << upper << " " << lower << " " << digit << endl; for (int i = 0; i < (int)s.length(); i++) { if (s[i] >= 'a' && s[i] <= 'z') s[i] = s[i] - 'a' + 'A'; } cout << s << endl; return 0; }

这道题需要特别注意的地方是getline和cin混用的问题。如果前面已经用cin >> n读过一个整数,再直接getline会读到一个换行符,导致字符串为空。解决办法是在cin后面加一句getline(cin, s);把多余的换行符吃掉,或者用cin.ignore()。这个问题在周赛里经常出现,一旦遇到就是整道题全错,非常可惜。

3.3 质数判断与循环优化

题面描述:输入一个正整数x(x不超过100000),判断它是否为质数。如果是,输出YES,否则输出NO。

质数判断是普及组循环题里的常青树。基础做法是从2循环到x-1,看有没有能整除x的数:

#include <iostream> using namespace std; int main() { int x; cin >> x; bool isPrime = true; if (x < 2) isPrime = false; for (int i = 2; i < x; i++) { if (x % i == 0) { isPrime = false; break; } } if (isPrime) cout << "YES" << endl; else cout << "NO" << endl; return 0; }

这个版本在x比较小的时候没问题,但x到100000时循环要跑近十万次,虽然也能过,但效率很差。第12周这道题的正解思路是只循环到sqrt(x)为止。因为如果一个数x有因子,它必定有一个因子小于等于sqrt(x)。这样循环次数骤降到几百次,速度提升非常明显。代码只需要把循环条件改成i * i <= x或者i <= sqrt(x)。

这题的易错点有两个。一个是忘记处理小于2的数,1既不是质数也不是合数,要单独考虑。另一个是用sqrt函数时没有包含#include <cmath>,或者用了sqrt(x)导致浮点误差。更稳妥的写法是for (int i = 2; i * i <= x; i++),直接用乘法避免开方。这种细节在赛题中很常见,平时写代码不养成好习惯,赛场上就会莫名其妙地错。

3.4 模拟题中的“状态机”思路

题面描述:有一台电梯,初始在第1层。输入一个正整数n,再输入n个数字,表示接下来要去哪几层。电梯每上升一层需要3秒,每下降一层需要2秒,每次到达目的地停留5秒。输出从初始状态出发,访问完所有目的地并返回第1层需要多少秒。

这道题是典型的“模拟题”,也就是用代码把现实场景一步一步跑一遍。它不需要什么高深算法,关键是理清状态变化。电梯当前在哪一层是一个状态,要去哪一层是目标状态,从当前状态到目标状态要计算上升或下降的层数。用一个变量记录当前位置,每读入一个目标楼层,就计算移动时间和停留时间,累加到总时间里,最后再计算回第1层的时间。

#include <iostream> using namespace std; int main() { int n; cin >> n; int cur = 1; int total = 0; for (int i = 0; i < n; i++) { int target; cin >> target; if (target > cur) { total += (target - cur) * 3; } else { total += (cur - target) * 2; } total += 5; cur = target; } // 返回第1层 total += (cur - 1) * 2; cout << total << endl; return 0; }

这种题对初学者的价值不是代码本身,而是建立“状态跟踪”的思维模型。很多孩子在读题的时候能算对样例,但写代码的时候不知道每一步该干什么,原因是没有抓住“当前楼层会变”这个关键状态。我教这类题时会把题目变成角色扮演:让孩子当电梯,我报楼层,孩子计算移动时间,每报一层就更新一次“当前楼层”。玩过两轮之后,孩子们写代码的准确率会大幅提升。

4. 参赛实战:60分钟里的时间分配与排查技巧

4.1 大家最容易忽略的时间策略

周赛虽然只有几道题,但60分钟的时限对普及组的孩子来说并不宽裕。我观察了很多次比赛,发现成绩不理想的孩子大多数不是因为题目做不出来,而是因为时间分配出了问题。最常见的情况是:在一道题上死磕了40分钟,结果后面三道会的题没时间写。我的建议是“两遍扫描法”。

第一遍:拿到卷子花3到5分钟把所有题目全部看一遍,把会做的、犹豫的、完全没思路的分别做标记。第二遍:从会做的题目开始写,优先保证这部分稳拿分;然后做犹豫的题,每道题最多给自己15分钟,做不出来就跳;最后还剩时间再回头啃完全没思路的题。这个策略说起来很简单,但实际操作中很多孩子就是忍不住跟一道题较劲。我在班里经常强调:竞赛不是把所有题都做出来才叫赢,把能拿的分全拿住已经是赢。

4.2 本地测试样例与边界数据的确认方法

第12周的赛题里有一半的题,测试数据都比样例数据要极端。所以只拿样例数据测完就交卷,是很危险的做法。我要求学生在写完代码后,额外构造至少三组测试数据:一组是题目允许范围内的最大规模数据,一组是最小边界数据,一组是随机中间值数据。

举个例子,如果题目说n不超过1000,就在本地测试n=1000的情况,看程序会不会超时或数组越界;如果题目涉及到“至少一个数所以结果非空”,就测试n=1的情况,确认初始值的处理是否正确。很多孩子的代码在样例上跑得飞快,一上大数据就崩,原因无外乎数组开小了或者循环边界没控制好。这些坑如果在本地提前踩过,到了正式评测就能避开。

另外一个特别实用的技巧是“对比法”。如果一对输入输出不确定对不对,可以先用Python之类的脚本语言写个暴力版本,对很小的随机数据跟C++程序对拍,结果不一致说明C++程序有bug。这个问题排查手段虽然听起来有点高级,但对普及组高年级的孩子来说完全可以掌握,能省下大量肉眼查错的时间。

4.3 初赛阶段最常见的五类报错现场

编译错误:最常见的不是语法不会,而是少写了分号、括号不匹配、变量名拼写不一致。这类错误编译器会报出来,让孩子养成先看第一条错误信息的习惯,修完一条再编译,不要对着满屏报错发呆。

运行时错误:常见原因有数组越界、除数为零、访问空字符串。第12周的题目里,除数为零的坑主要体现在“平均分”之类的题上,如果n可能为0,先判断再算除法。

答案错误:程序能跑但结果不对,这种往往是最难查的,因为错在逻辑而不是语法。建议从头到尾手推一遍样例,看哪一步跟题目给的结果不同,锁定出错区间。

超时:第12周出现超时的主要是质数判断那类题,三层循环嵌套对入门组的孩子杀伤力很大。优化方向是先找出循环最内层做了什么多余操作。

输出格式错误:多了一个空格、少了一个换行,都算错。这个没有技术含量,纯粹靠审题仔细。让孩子在提交前把cout语句逐个跟题目对照一遍,尤其注意最后一行的输出有没有换行。

5. 从第12周往后:接住这个分水岭

第12周在秋季学期的安排中有着特殊的位置。往前看,它是前面所有内容的综合演练;往后看,它是提高组内容的起点。那些在本次周赛里表现不俗的孩子,接下来就可以开始接触枚举算法、排序、简单数据结构了。而还没完全掌握基础的孩子,也不必焦虑,因为普及奠基组的意义就在于把语言地基打牢,宁可慢一点,也不要夹生。

我对家长有一个建议:这个阶段不要急着给孩子报更高阶的班,也不要因为一次周赛成绩波动就给孩子加码。编程说到底是一门实践学科,孩子需要的是每周固定的练习量和复盘习惯,而不是临时抱佛脚式的题海战术。让孩子每次周赛后做三件事:把错题重做一遍、把不会的题对照标准代码逐行读一遍、在草稿纸上画一画每道题的思路图。这三件事坚持做,比刷十套模拟卷都管用。

我自己带过很多孩子度过了这个阶段。一个很普遍的规律是:第12周前后正是两极分化的起点,但分化方向不取决于天赋,而取决于每周那个把错题弄懂的动作有没有做到位。语言普及组真正的意义,就是在这个分化还没拉开的时候,给孩子足够的试错空间和纠偏机会。第12周赛题再综合,翻来覆去考的仍然是最核心的循环、分支、数组三件套。把这三件事玩明白,后面的提高之路自然就顺了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 4:11:34

Java数字签名与证书实战:从原理到代码完整解析

数字签名和证书这块&#xff0c;我在 Java 生态里算是踩过不少坑才真正弄明白的。光看 API 文档&#xff0c;总觉得每个类都认识&#xff0c;但真到自己签发证书、验证签名的时候&#xff0c;就发现还有一堆隐含的约定、格式细节和 JDK 版本差异在等着你。这篇东西&#xff0c;…

作者头像 李华
网站建设 2026/10/17 4:11:14

旋转目标检测OBB:从YOLOv5原理到C++多相机部署

1. 旋转目标检测&#xff1a;从一个“坑爹”的需求说起如果只是做普通的目标检测&#xff0c;YOLOv5 的生态足够成熟&#xff0c;轮不到 OBB 这个变体出来折腾。但现实里总有那么一类场景&#xff0c;水平框根本扛不住——无人机俯拍的密集停车场、遥感图像里的任意朝向船只、工…

作者头像 李华
网站建设 2026/10/17 4:09:54

从千元创意到大模型迭代:独立开发者的机遇与生存法则

我平时有个习惯&#xff0c;每天早上把各个科技资讯源过一遍&#xff0c;不是为了追热点&#xff0c;主要是想看行业里那股水往哪个方向流。今天几条消息放在一起&#xff0c;信息量其实不小&#xff1a;一个由三位95后开发者花一千多元做出来的创意App&#xff0c;被传出估值到…

作者头像 李华
网站建设 2026/10/17 4:09:54

基于SSM的JavaWeb购物商城项目实战:登录购物车与防超卖

简介&#xff1a;JavaWeb购物商城是一套基于JSP、Servlet与MySQL实现的小型在线商店项目源码&#xff0c;主要面向正在学习JavaWeb开发的学生、需要完成课程设计或毕业设计的开发者&#xff0c;也适合想快速搭建商城演示项目的初学者。项目将用户界面、请求控制、业务逻辑与数据…

作者头像 李华
网站建设 2026/10/17 4:08:39

FT-232 USB转串口驱动:Windows/macOS/Linux三系统安装与排障指南

简介&#xff1a;Z-TEK&#xff08;力特&#xff09;FT-232 USB转串口驱动是一款基于FT232芯片的多系统通用资源&#xff0c;面向需要连接RS-232设备&#xff08;如Modem、PDA、工业仪表&#xff09;的嵌入式开发者、运维人员及电子爱好者。驱动符合USB2.0标准&#xff0c;传输…

作者头像 李华
网站建设 2026/10/17 4:06:39

Tcl/Tk 串口监听工具实战:事件驱动与二进制帧解析

简介&#xff1a;面向Tcl/Tk开发者的串口通信实战资源包&#xff0c;覆盖从入门到进阶的常见场景&#xff0c;尤其适合嵌入式、工业控制和物联网开发者在设备联调时使用&#xff0c;以脚本方式快速实现串口收发与界面交互。压缩包共134个文件&#xff0c;主体为53个tcl脚本&…

作者头像 李华