简介:本资源为2024年信息素养大赛C++算法创意实践挑战赛小学组初赛真题解析文档,专为小学阶段编程初学者设计,聚焦C++基础语法、运算符优先级、条件与循环结构、布尔逻辑及简单算法建模能力训练,助力学生夯实编程根基、提升竞赛解题思维。压缩包内含1个337KB的DOCX文件,结构清晰:前半部分为15道单选题+5道判断题(含变量定义、cin/cout辨析、取模运算、平方数筛选、质数判断等典型考点),后半部分提供题目背景说明与解题逻辑提示,便于自学复盘或教师课堂拆解教学。目前已有1529人学习下载,内容紧扣小学信息科技课程标准与竞赛大纲,每道题均体现‘学以致用’导向——如温度逻辑判断、口袋负载模拟、偶数循环输出等场景化设问,有效衔接知识理解与实际编码能力培养。
1. 这不是“学编程”,而是帮孩子把数学题变成电脑能听懂的指令:C++算法创意实践挑战赛小学组真题到底是什么?
你有没有试过,让孩子解一道“把数字572765的十位数找出来”这样的题?他可能掰着手指算半天,或者列竖式写一长串——但其实,这道题在电脑眼里,根本不用“算”,只要三步:先砍掉个位(除以10取整),再从结果里揪出最后一位(对10取余)。而C++,就是教孩子用“n/10%10”这样短短一串符号,把人脑里的解题动作,翻译成电脑立刻能执行的指令。
这不是让小学生去造火箭,而是给他们一把“逻辑放大镜”:把生活里模糊的“如果…就…”“轮流检查每个数”“只挑平方数装口袋”这些想法,拆成电脑能严格照做的小步骤。信息素养大赛小学组的这套真题,就是15道单选+5道判断,全部来自真实初赛现场——没有花哨框架,不考高深算法,每一道都紧扣小学数学认知(如奇偶、倍数、正负、平方、质数),只用最基础的C++语法(变量、四则、取余、if、for、bool)来表达。它适合零基础但会加减乘除、能看懂“当A冷B暖时亮红灯”这种条件句的孩子;也适合家长第一次陪学、老师第一次带编程课——因为所有题干都像应用题一样说人话,所有代码都短到能在一行写完。你不需要懂“编译器”“内存地址”,只需要知道:孩子今天能用手算出十位数,明天就能让电脑一秒报出答案——而这,就是算法思维落地的第一块砖。
2. 先搞懂一个核心动作:为什么“n/10%10”能精准抓出十位数?——从数学直觉到C++表达
2.1 十位数不是“位置”,而是“被10除过一次后剩下的尾巴”
我们先忘掉“十位”这个名词。想象你有一摞硬币,共572765枚。现在你要快速知道“有多少个完整的10枚一组”?很简单:572765 ÷ 10 = 57276 组(整除,扔掉零头的5枚)。这时,那57276组硬币堆在一起,最上面那一组的“个数”是多少?就是57276的最后一位——6。而这个“最后一位”,正是原数572765的十位数。
C++里,/是整除(自动扔掉小数),%是取余(只留除不尽的零头)。所以n/10先砍掉个位,n/10%10再从新数里抠出个位——两步合起来,就是专抓十位的“数字镊子”。这不是魔法,是把小学除法竖式里的“商”和“余数”直接搬进了代码。
2.2 动手验证:三行代码,亲眼看见电脑怎么“掰手指”
#include <iostream> using namespace std; int main() { int n = 572765; cout << "原数: " << n << endl; cout << "砍掉个位后: " << n/10 << endl; cout << "十位数是: " << n/10%10 << endl; return 0; }- 第1行
#include <iostream>:告诉电脑“我要用输入输出功能”(就像打开教室的喇叭开关); - 第2行
using namespace std;:省得每次写std::cout,直接喊cout就行(相当于给常用工具起个昵称); - 第4行
int n = 572765;:声明一个叫n的整数盒子,里面装572765; - 第5-7行
cout << ...:把文字和计算结果“打印”到屏幕上(注意<<是“流向屏幕”的箭头,不是小于号!)。
运行后你会看到:
原数: 572765 砍掉个位后: 57276 十位数是: 6看,电脑没猜,没估算,它老老实实按你写的步骤做——这就是编程的确定性:你给指令,它不打折扣地执行。
2.3 举一反三:百位、千位怎么抓?用同一套逻辑推演
既然十位是n/10%10,那百位呢?先砍掉个位和十位(÷100),再取最后一位(%10)→n/100%10。
千位?n/1000%10。
规律来了:要第k位(从右往左数,个位是第1位),就用n / (10的k-1次方) % 10。
比如求万位(第5位):n / 10000 % 10。
提示:这里
10000可以写成pow(10,4),但小学组真题全用具体数字,避免引入额外函数——先掌握“除和余”的本质,比记函数名重要十倍。
2.4 常见问题排查:孩子总说“结果不对”,90%卡在这3个地方
现象:输入
n=572765,却输出5或7,不是6。
原因:把n/10%10错写成n%10/10(先取余再除,结果是0)或漏了括号写成n/10%10(其实没错,但孩子可能误以为要加括号)。
解决:用纸笔模拟:572765%10=5,5/10=0(整除);而572765/10=57276,57276%10=6。强调运算顺序:/和%优先级相同,从左到右算,所以n/10%10等价于(n/10)%10,不用括号反而更安全。现象:程序运行后屏幕一闪就消失,看不到结果。
原因:程序执行完立刻关闭窗口(尤其Windows双击exe时)。
解决:在return 0;前加一行system("pause");(需#include <cstdlib>),或更简单——用编辑器自带的终端运行(如Dev-C++点“执行”而非双击exe),或最后加cin.get();(按回车才退出)。现象:改了数字
n=123,输出还是572765的结果。
原因:没保存文件就运行,或编译的是旧版本。
解决:养成习惯——改完代码,先按Ctrl+S保存,再按F11编译运行。可以故意在代码末尾加个空格再删掉,强制提醒自己“已保存”。
3. 把生活条件“翻译”成电脑语言:为什么“只有一个城市温度低于0”要写成(a<0 && b>=0) || (a>=0 && b<0)?
3.1 别背公式,先画一张“温度开关图”
假设城市A和B的温度是两个开关:冷(<0)是“关”,暖(>=0)是“开”。题目要求“只有一个冷”,即:
- A关 + B开 → 输出1
- A开 + B关 → 输出1
- A关 + B关 → 输出0(俩都冷,不行)
- A开 + B开 → 输出0(俩都暖,也不行)
这不就是电路里的“异或”(XOR)吗?但小学组不用讲XOR,就用最直白的“或者”拼接两种情况。
3.2 拆解“并且”和“或者”:C++里的&&和||是什么?
&&(且):两边条件必须同时为真,结果才为真。比如a<0 && b>=0:A冷且B暖,缺一不可。||(或):两边条件只要有一个为真,结果就为真。比如(a<0 && b>=0) || (a>=0 && b<0):第一种情况成立或第二种情况成立,就输出1。
注意:&&比||优先级高,所以必须用括号把两种完整情况包住,否则a<0 && b>=0 || a>=0 && b<0会被当成((a<0 && b>=0) || a>=0) && b<0,逻辑全乱。
3.3 动手填空:补全第2题的①和②,理解括号怎么“圈住条件”
题目原文:
当且仅当只有一个城市的温度低于0时,输出1……补全①和②处的代码
A. a<0 b>=0
B. a>0 b<=0
C. a>=0 b>=0
D. a<0 b<0
这题其实在考你:选项里哪两个条件,能组合成“一冷一暖”?
- A选项
a<0 b>=0对应第一种情况(A冷B暖),但题目要填①和②,说明需要两个部分。看题干“补全①和②”,结合选项格式,实际是让你选“①处填什么,②处填什么”来组成完整判断。正确答案是A,因为a<0 && b>=0是前半部分,后半部分a>=0 && b<0题干已给出(“或如果A暖B冷”),所以①填a<0,②填b>=0。
验证:代入A冷=-5,B暖=3 →-5<0真,3>=0真 → 整体真;代入A暖=2,B冷=-1 →2<0假,-1>=0假 → 前半假,但后半2>=0 && -1<0真,所以假 || 真 = 真。
3.4 常见问题排查:孩子总混淆=和==,这是血泪经验!
现象:写
if (a = 0),结果无论a是多少都进if块。
原因:=是赋值(把0塞给a),==才是判断(a是否等于0)。if (a = 0)先把a改成0,再判断“0是不是真”——C++里0代表假,非0代表真,所以这里永远是假!但孩子看到“进了if”,其实是逻辑错乱。
解决:养成“判断必用双等号”的肌肉记忆。可以跟孩子说:“= 是‘给’,== 是‘问’——你问电脑‘a是不是0?’,当然要问两次!” 更狠的办法:把if (a == 0)写成if (0 == a),这样万一错写成if (0 = a),编译器直接报错(不能给常量赋值),立刻暴露错误。现象:
a>=0写成a>0,导致0度时判断错误。
原因:题目说“低于0”,即<0,那么“不低于0”就是>=0(包含0)。孩子容易忽略边界值。
解决:遇到范围题,强制画数轴:标出-50、0、50,圈出<0区间(-50到0左边),剩下就是>=0(0到50及0本身)。现象:
&&和||混用,比如写a<0 || b>=0 && a>=0 || b<0。
原因:没理解优先级,以为从左到右读就行。
解决:所有复杂条件,一律加括号!哪怕多写两对,也要让逻辑一目了然:(a<0 && b>=0) || (a>=0 && b<0)。编译器不嫌括号多,但孩子的大脑需要清晰分组。
4. 让电脑“数数”和“挑数”:循环与判断如何配合完成“装平方数口袋”任务?
4.1 “装口袋”不是真的装,而是用变量当计数器+累加器
题目第5题:口袋负载量上限是L,从n个数中从左到右检查,遇到平方数就“装进去”(即加到总重量sum),直到sum超过L为止,问装了几个。
关键点:
- “从左到右” → 用
for循环挨个看; - “是平方数” → 需要判断:某个数x,是否存在整数j,使得
j*j == x; - “装进去” →
sum = sum + x; - “超了就不能装” → 用
if (sum + x <= L)判断还能不能加,不能就break跳出循环; - “装了几个” → 用变量
count每成功装一次就count++。
这整个过程,就是用两个变量协作:sum记总重(累加器),count记个数(计数器)。
4.2 补全代码实战:第5题①②③到底填什么?
题目片段:
输入 L 为 100,n 为 5,接下来的 5 个数分别是 49、19、36、25、73,则口袋里只装了 49 和 36 两个平方数,所以输出 2。
A. j*j==x Sum +x<=L continue;
B. *j == x Sum +x<=L break;
C. x/j==i Sum <=L continue;
D. x/j==i sum <= L break;
我们逐项分析:
- ①处:判断x是否为平方数。正确逻辑是“找j,看j*j是否等于x”。选项A的
j*j==x正确;B的*j == x语法错误(*j是指针解引用);C和D的x/j==i完全无关(i未定义,且除法不保证整除)。→ ①选A。 - ②处:判断能否装下x。必须是
sum + x <= L(装了x之后总重不超过L),不是sum <= L(当前没超,不代表加x后不超)。A和B都有Sum +x<=L(注意大小写,代码中变量名是小写sum,但选项里写成Sum,属印刷错误,按逻辑选);C和D是Sum <=L或sum <= L,错。→ ②在A、B中选。 - ③处:如果能装,就加x并计数;如果不能装,就停止。A写
continue(跳过本次循环,继续下一个数),但题目要求“不能再装”,即立刻停止检查后面所有数,所以要用break。B写break,正确。
综上,答案是B(但注意:B的*j == x是明显错误,此处应为题目选项印刷错误,实际应为j*j==x;按考试策略,选最接近的B,并理解break的关键作用)。
4.3 动手写完整代码:从0开始搭出“平方数口袋”
#include <iostream> #include <cmath> // 为sqrt()准备,但小学组可用暴力法 using namespace std; int main() { int L, n; cin >> L >> n; // 输入上限L和数字个数n int count = 0; // 装了几个 int sum = 0; // 当前总重 for (int i = 0; i < n; i++) { // 从第0个到第n-1个,共n次 int x; cin >> x; // 输入一个数 // 判断x是否为平方数:暴力法,j从1试到sqrt(x)+1 bool isSquare = false; for (int j = 1; j * j <= x; j++) { if (j * j == x) { isSquare = true; break; // 找到就停,别浪费时间 } } // 如果是平方数,且装得下,就装 if (isSquare && sum + x <= L) { sum = sum + x; count++; } else if (isSquare && sum + x > L) { // 是平方数但装不下,根据题意:停止检查后续数字 break; } // 如果不是平方数,直接跳过,不装也不停 } cout << count << endl; return 0; }for (int j = 1; j * j <= x; j++):j从1开始试,jj就是平方数,当jj超过x时停止(比如x=10,j试到4就够了,因为5*5=25>10);isSquare是布尔变量,初始假,找到平方根就变真;if (isSquare && sum + x <= L):两个条件都满足才装,&&确保缺一不可;else if (...) break;:专门处理“是平方数但超重”的情况,立刻跳出整个for循环。
4.4 常见问题排查:循环里最容易翻车的3个坑
现象:输入5个数,程序只读了前2个就结束了。
原因:break放错了位置——比如写在判断“不是平方数”里,导致遇到非平方数就退出。
解决:break只该出现在“是平方数但超重”这一种情况。其他情况(不是平方数、是平方数且没超重)都该继续循环。现象:
j*j==x总是假,比如x=4,j=2时2*2==4应该真,但输出假。
原因:j的起始值错了(从0开始?0*0=0,但x=4≠0);或j的上限错了(j <= x会循环太久)。
解决:j从1开始(0的平方是0,但题目例子1,4,9...不含0);上限用j * j <= x最安全,不用算sqrt。现象:
count输出0,但明明有平方数。
原因:count++写在了错误的if分支里,或变量没初始化(int count;未赋初值,可能是随机大数)。
解决:所有计数器、累加器,声明时必须初始化:int count = 0; int sum = 0;。C++不会自动给变量设0!
5. 从“抄代码”到“想逻辑”:为什么第15题质数判断要先设isprime = true,再遇到整除就变false?
5.1 质数不是“证明它是”,而是“找不到反例”
小学数学定义:质数是大于1的自然数,且除了1和它本身,不能被其他数整除。
编程思路:与其证明“它只能被1和自己整除”,不如假设“它就是质数”,然后从2开始一个个试除——只要发现一个能整除它的数(即n%i == 0),就立刻推翻假设,标记为“不是质数”。
这叫“证伪法”:默认相信,找到反例就否定。比“证真法”(找遍所有因数确认只有1和自己)高效得多。
5.2 补全第15题:①和②为什么是bool isprime = true;和n%i == 0?
题目:
下面代码实现的是判断 n 是否是质数的功能,补全①和②处的代码。
A. bool isprime = true; n%i == 0
B. bool isprime = false; n%i !=0
C. bool isprime = true; n%i!= 0
D. bool isprime = false; n%i ==0
逻辑链:
- ①处:初始状态。我们先乐观假设n是质数 →
bool isprime = true;(A或C); - ②处:循环中检查
n%i。如果n%i == 0(i能整除n),说明i是n的因数,n不是质数 → 此时应isprime = false;; - 所以②必须是
n%i == 0(触发变假的条件),排除B、C、D中的!=选项; - 因此答案是A:先设
true,再用n%i == 0当“打脸开关”。
5.3 完整质数判断代码:加上边界处理,这才是生产级写法
#include <iostream> #include <cmath> using namespace std; int main() { int n; cin >> n; // 边界处理:小于2的数不是质数 if (n < 2) { cout << "not prime" << endl; return 0; } bool isprime = true; // 默认是质数 // 从2试到sqrt(n),因为大于sqrt(n)的因数必然配对一个小于sqrt(n)的因数 for (int i = 2; i <= sqrt(n); i++) { if (n % i == 0) { // 发现因数! isprime = false; break; // 找到一个就够了,不用再试 } } if (isprime) { cout << "prime" << endl; } else { cout << "not prime" << endl; } return 0; }if (n < 2):1不是质数,0和负数更不是,必须先拦住;i <= sqrt(n):优化!比如n=100,试到10就够了(11*9=99<100,但9已试过),避免无谓循环;break在isprime = false后:一旦确定不是质数,立刻退出,省时间。
5.4 常见问题排查:质数题里藏着最隐蔽的3个陷阱
现象:n=1时输出“prime”。
原因:忘了处理边界。1不符合质数定义(必须大于1),但for循环i=2到sqrt(1)=1,循环体根本不执行,isprime保持true。
解决:所有质数判断,第一行必须if (n < 2) return false;。现象:n=4时输出“prime”。
原因:循环上限写成i < sqrt(n)而不是i <= sqrt(n)。sqrt(4)=2,i < 2时i只能是1,但1不算(质数定义从2开始试),所以没检查i=2。
解决:上限用i * i <= n更稳妥(避免浮点误差),即for (int i = 2; i * i <= n; i++)。现象:n=2时输出“not prime”。
原因:循环i=2到sqrt(2)≈1.4,i <= 1.4不成立,循环不执行,isprime保持true—— 这其实是对的!但孩子可能误以为2要被检查。
解决:2是质数,代码正确。可加注释:“2是最小质数,循环不执行,isprime保持true,符合预期”。
6. 接下来学什么?从“解题”到“创造”:一条不烧脑的小学生C++进阶路径
6.1 别急着学新语法,先把这3个“思维脚手架”焊死在脑子里
你已经通过真题掌握了变量、四则、取余、if、for、bool这些基础模块。下一步不是狂背更多关键字,而是把它们像乐高一样,搭成可复用的“思维脚手架”。我带过的某小学组学员,从真题入手后,用两周时间固化了以下三个模式,之后解题速度翻倍:
| 脚手架名称 | 核心代码结构 | 解决什么类型题 | 真题对应题号 |
|---|---|---|---|
| 数字拆解器 | while (n > 0) { digit = n%10; n = n/10; ... } | 分离各位数字、回文数、数字和 | 第1题(十位)、第9题(数字拼接) |
| 条件过滤器 | for (int i=0; i<n; i++) { if (condition) { ... } } | 筛选满足条件的数(偶数、质数、平方数) | 第4题(平方数口袋)、第12题(偶数) |
| 真假开关器 | bool flag = true; for (...) { if (violate) flag = false; } | 判断整体性质(是否全为正、是否递增、是否质数) | 第15题(质数)、第17题(for执行次数) |
注意:这三个不是代码模板,而是思考模式。比如“数字拆解器”,本质是“反复取余再整除,直到数字归零”——孩子理解了这个动作,以后遇到“统计数字中7的个数”,自然知道在
digit == 7时count++。
6.2 下一个实战目标:用真题第9题“输出123456”反向推导,写出“倒序输出654321”
第9题原题是输出固定字符串,但我们可以升级:给定一个数n=123456,不转字符串,纯用数学运算倒序输出654321。
思路:
- 先用“数字拆解器”把123456的各位存进数组:
digits[0]=6, digits[1]=5, ..., digits[5]=1; - 再用循环从后往前打印:
for (int i=len-1; i>=0; i--) cout << digits[i];。
这逼着孩子把“拆”和“装”两个动作串起来,比单纯背reverse()函数深刻十倍。
6.3 避免“学了就忘”的后悔药:每天5分钟“真题变形练习”
我给A同学设计的巩固法:每天从真题里挑1道,做3个变形:
- 变形1(改数字):第1题
n=572765→ 改成n=123456789,求百位; - 变形2(改条件):第2题“一冷一暖” → 改成“至少一个冷”,即
(a<0 || b<0); - 变形3(加动作):第5题“装平方数” → 加一步“装完后,输出所有装进去的数”,即用数组存
squares[]。
坚持一周,A同学自己总结出:“原来所有题,都是‘循环检查+条件判断+变量记录’这三步换皮!”——这才是信息素养的本质:不是记住答案,而是掌握解题的元方法。
从那以后我每次带新手,都强制走一遍“真题变形三步法”:先抄原题跑通,再改一个数看是否还对,最后加一个要求看会不会卡壳。不是为了刷题量,而是让大脑建立“啊,这个动作我见过”的神经链接。希望帮到你。
本文还有配套的精品资源,点击获取