每次带备考班的同学刷题,碰到“数位之和”这道二级真题,我都能预见两种反应:刚入门的小朋友觉得太简单,三分钟写完提交,结果因为小细节扣了分;另一部分同学则是被“数位”两个字绕晕,上来就问“老师,数位是什么意思,是不是和数位顺序表那个数位一样”。作为一道出现在2024年9月二级试卷里的真题,“数位之和”考的不是什么高深算法,而是编程里最基础也最核心的两个能力:通过整除和取余拆解一个数的每一位,再用循环把拆出来的数累加起来。这篇内容不打算只念一遍题解,我会把这道题背后的出题意图、从读题到提交的完整思路、不同语言写法的差异、以及考试里最容易丢分的几个隐蔽坑全部拆开讲透,适合正在备考二级的学员,也适合带学员刷题的老师参考。
1. 这道二级真题练的是什么:拆解考官的出题意图
先说一个很多人不信的结论:二级考试里真正拉分的,往往不是最后那道看起来复杂的题,而是“数位之和”这种大多数人都能写出来、却只有少数人能满分通过的题目。原因很简单,这道题覆盖率足够广,出题人要同时照顾到继续深造的学员和刚学完循环的初学者,所以它必须看起来不难,但暗含几个必须踩准的知识点。
1.1 从题目分值看考察重点
以常见的题型为例,这类题目一般给一个正整数n,要求计算它的各位数字之和。比如输入123,每位数分别是1、2、3,加起来是6;输入4096,拆开是4、0、9、6,和是19。题目描述通常不会拐弯抹角,但它完整覆盖了二级考纲里这几个要求:
- 数据类型和输入:能正确读入一个整数;
- 循环结构:能用循环控制拆分的次数;
- 整除和取余的混合运用:
/和%的组合是拆位的基础; - 累加器思想:先定义变量存总和,再在循环里不停往上加;
- 格式化输出:用
print或cout输出最终结果。
如果这五个点任何一个没真正理解,代码可能都能跑,但你心里是虚的。比如有的同学会把累加器定义在循环里,每次累加都被重置为0,输出永远是最后一位的数,这种错误特别经典。
1.2 数位拆分是所有后续题型的基石
往长远看,“数位之和”这一类题并不只是二级考试的一个孤立考点。它背后的数位拆分思想,会一直跟着你走到很多更复杂的题目里:比如判断一个数是不是回文数,需要把每一位倒着重新组合;比如水仙花数,需要对每一位做三次方再求和;再比如统计某个数字在区间里出现了多少次,也要逐位拆开数。换句话说,这道题是后续很多算法题的“元技能”。
我经常和学员打一个比方:数位拆分就像学做饭时的切菜。切菜本身不直接是一道菜,但所有菜几乎都离不开切这个动作。如果你今天在这道“数位之和”上把切菜切熟练了,后面做回文数、做进制转换、做数字统计,都会顺很多。所以别把它当一道可以糊弄过去的小题,在这道题上花的每一分钟都是为后面省时间。
2. 核心算法拆解:取个位与删个位的循环组合
理解了出题意图,接下来我们要解决最核心的问题:给一个正整数,我怎么才能把它每一位都拿出来?答案就藏在两个基础运算里:十进制下对10取余,和整除10。
2.1 两个基础运算各自的边界
先说第一个运算:n % 10,这是“取个位”的操作。任何正整数除以10的余数,一定是它最后一位数字。123 % 10 = 3,4096 % 10 = 6,这个规则对任意多位数都成立,因为整十整百的部分都能被10整除,剩下的就是落在个位上的余数。
再说第二个运算:n // 10(Python里是整除,C++里直接用/),这是“删个位”的操作。123 // 10 = 12,4096 // 10 = 409。原来在十位上的数字,经过整除后挪到了个位。这两个运算放在一起就是一个完美的“拆一位”组合:先用取余把当前最后一位拿出来,再用整除把这位从数字里删掉。
所以循环内的基本步骤可以写成:
digit = n % 10 # 取出当前最后一位 total += digit # 累加到总和中 n = n // 10 # 删掉当前最后一位这个组合之所以经典,是因为它不依赖你知道这个数有几位数。不管是10、100还是99999,循环都会自动执行到所有位都被删完为止。如果你用字符串转换的方法,代码确实也能过,但对于二级考试来说,用整除和取余才是更接近“编程思维”的解法,后面我会专门对比这两种写法。
2.2 循环终止条件:为什么用 while n > 0
拆位的过程天然适合while循环,因为循环次数不固定,取决于输入数字的位数。while n > 0表示“只要这个数还没被删成0,就继续拆”。
这里要特别强调一个细节:判断标准是n > 0而不是n >= 0。如果写成>= 0,程序会进入死循环——因为0 // 10还是0,这个循环永远不会自己结束。我在答疑时见过好几个同学在这个地方卡住,运行明明没报错,但程序就是结束不了,最后发现就是多写了一个等号。
另外,while n != 0和while n > 0在这道题里完全等价,因为正整数拆到结尾必然是0。但如果你后面升级做数字根、统计负数位和之类的题目,n != 0会更通用。
2.3 特别讨论输入为0的情况
真题里这道题一般不会输入0,因为题目通常写的是“正整数”。但放到评测系统里,边界测试数据有时候会让你措手不及。
如果输入是0,按照while n > 0的逻辑,循环一次都不进,总和保持初始值0,直接输出0。这个结果恰好是对的,因为“0”这个数位之和确实是0。如果你想对这道题做一点加固,可以在读入后直接加一行判断if n == 0: print(0),不过一般来说没必要,但理解了这个边界,你在写更复杂的数位题时心里会更有底。
3. Python解法实战:从读题到提交的完整过程
下面用Python把这道题完整过一遍。Python语法简洁,非常适合初学者先建立“拆位+累加”的思维模型。
3.1 代码逐段精讲
完整的参考代码如下:
n = int(input()) # 读入一个正整数 total = 0 # 累加器,保存数位之和 while n > 0: total += n % 10 # 取出当前个位,加入总和 n //= 10 # 删除当前个位 print(total) # 输出数位之和逐段拆开看:
第一行int(input())负责输入处理。评测系统里一般一行只有一个整数,用默认的input()读一行再转成int就够了。这里有个容易被忽略的坑:如果用input().split()想处理多个数字,但本题输入就一个整数,那属于画蛇添足,反而容易在转类型时报错。
第二行total = 0是累加器的初始化。这个变量必须定义在循环外面,否则每次循环它都会被重置成0,结果永远是最后一个数字。很多同学第一次写循环累加时都会踩这个坑,我甚至在考场上见过有人输出“3”,因为他输入的是123,每次进循环total都被重置,最后只留下了最后一位3。
第三到五行是核心循环。n % 10取出当前最低位的数字,加进total;n //= 10把这一位从原数字里删掉。注意我用了//,Python里直接写/会得到浮点数,比如123 / 10 = 12.3,再执行n % 10就会出错,因为浮点数取余的语义和整数不同。这是Python写法里最容易翻车的点。
最后一行的print(total)输出结果。评测系统只关心输出内容是否与标准答案一致,所以不需要加多余的提示语句,比如print("sum =", total)在标准评测里反而会因为多了字符被判错。
3.2 最容易白丢分的4个细节
结合我批改过的几百份作业,Python解法里最常见的扣分点集中在这几处:
| 问题 | 错误示例 | 正确写法 | 后果 |
|---|---|---|---|
| 累加器位置 | 把total = 0写在循环内部 | 写在循环前 | 只累加最后一位,结果错误 |
| 整除符号 | n = n / 10 | n = n // 10 | 出现浮点数,取余结果异常或直接报错 |
| 循环条件 | while n >= 0 | while n > 0 | 死循环,程序超时,0分 |
| 输出多余内容 | print("结果是:", total) | print(total) | 评测系统判定输出格式不符,即使答案数值对也只能拿部分分或0分 |
第四个问题在真实考试里特别冤。有的同学在自己电脑的IDE里跑得好好的,也看到了正确结果,但忘了评测系统是机器比对标准输出。你多打印一个冒号、一个空格,全都算“输出错误”。所以从平时刷题开始,就要养成“输出什么就是什么,不多不少”的习惯。
4. C++解法与不同语言的实现差异
很多学校的信息学课程用的是C++,所以这道题在二级考试里也会以C++形式出现。C++的写法其实和Python非常像,核心逻辑完全一致,只差语法细节。
4.1 C++代码与注意事项
参考代码如下:
#include <iostream> using namespace std; int main() { int n; cin >> n; int total = 0; while (n > 0) { total += n % 10; n /= 10; } cout << total << endl; return 0; }C++里要注意的是它没有//这种写成两行的整除运算符,n / 10在两个整数之间做除法时,天然就是整除,结果直接截断小数部分。这就是C++里比较直接的一个地方:两个int相除,结果永远是int。123 / 10的结果就是12,系统自动丢掉.3。
另外C++里建议把n声明为long long而不是int。因为“数位之和”类的题目有时候会把范围放宽,或者告诉你最大可以到多少位,如果测试数据超过了int的表示上限(约21亿),用int就会溢出,运行时得到的结果可能是错的。反正考试环境一般不会限制你用long long,稳妥一点没坏处:
long long n; cin >> n;4.2 做题时选Python还是C++
经常有学员问我:既然两种写法都能做对,我到底该用哪个?我的建议是:看你的主语言。如果你平时练的是Python,就坚定用Python,不要在考场上临时切到C++;反过来也一样。二级考试的判分看的是最终答案,不是看你用了多高级的写法,所以用你最熟练的语言提交就是最优解。
但如果是在学习阶段,我建议至少把两种写法都亲手敲一遍。原因是Python代码短、容易理解,适合先把“取余+整除”的逻辑彻底搞明白;C++写起来繁一点,但又会让你去思考类型、溢出、输入流这些Python帮你隐藏掉的底层细节。两者对照着学,知识点会记得更牢固。
5. 一道题远远不够:数位题的变体与进阶方向
把“数位之和”的基础算法吃透之后,你会发现市面上很多看起来花哨的题目,其实都是在它的骨架上加了不同的外壳。这里我列几个最常出现的变形,每一个都值得自己动手改一改。
5.1 常见的四种变形考法
| 变形方向 | 典型问法 | 与基础版的差异 |
|---|---|---|
| 求和变求积 | 计算各位数字的乘积 | 累加器改成连乘,初始值从0改成1,还要小心数字中含有0 |
| 带条件筛选 | 只统计偶数的数位 | 循环里加if digit % 2 == 0判断 |
| 数字根问题 | 反复求数位之和,直到结果为一位数 | 外层再套一个循环,或找到数学规律 |
| 没有输入个数的统计 | 连续读入若干个数字,分别输出各自的数位之和 | 循环外面再套一层循环,注意变量重置 |
以“求各位数字的乘积”为例:演示代码几乎只需要改两行:
n = int(input()) product = 1 # 乘积的初始值必须是1,不能是0 while n > 0: product *= n % 10 n //= 10 print(product)这个变形最阴险的地方是初始值。如果是累加,初始值0很自然;但累乘用0当初始值,所有结果都会变成0。题目只要稍微变一下,很多同学就把基础原理忘了,直接栽在初始值上。这提醒我们:不要只背代码,要理解每一步操作的原因。
5.2 从“数位之和”到“数位统计”
还有一种更进阶的变体:给你一个区间[a, b],让你统计里面有多少个数字满足“各位数字之和等于某个指定值”。这种题看着难,但它本质上就是“数位之和”加一层外层循环:
a, b, target = map(int, input().split()) count = 0 for n in range(a, b + 1): total = 0 temp = n # 不能直接改n,否则外层循环会乱 while temp > 0: total += temp % 10 temp //= 10 if total == target: count += 1 print(count)这里有个很容易踩的坑:内层循环拆位的时候,必须用一个临时变量temp来操作,不能直接拿n去拆,否则外层for循环的变量被改掉了,整个遍历就乱了。很多学员第一次写这种嵌套结构,总想着“省一个变量”,结果循环只跑了一次就退出,半天找不出原因。
这类题目就是“数位之和”价值的直接体现:你在基础题上练得越熟,迁到这些复杂场景里就越游刃有余。
6. 备考建议与常见失分点复盘
最后聊一点实在的应考经验。二级考试的“数位之和”虽然不难,但它在整张试卷里的定位,更接近“保分题”。如果这道题失分,多半不是因为你不会,而是因为细节没做到位。
6.1 测评系统的输出要求
评测系统判题时是拿你的程序输出和标准答案文件逐字符比对的。这意味着:
- 输出不能多一个空格、少一个换行;
- 输出不能带任何中文或提示文字;
- 需要输出换行的地方不能省略(不过
print和cout << endl默认都会加,一般不用担心)。
我习惯在考试前再三叮嘱学员:把最后几行代码反反复复看上两遍,不要让print(total, end=' ')这种自己为了调试方便加上的东西留在文件里。如果你平时在自己电脑上调试时会打印中间变量,提交之前记得把那些调试语句全部删掉。
6.2 考前怎么练这一类循环题
备考阶段,与其刷十道不同类型的题,不如把一道经典题一口气变着花样写五遍。比如今天吃透“数位之和”,明天就做“各位数字之积”,后天做“统计区间内满足数位和的数字个数”。每一次改写,你都会对循环、取余、整除这三个动作产生更深的理解。
如果时间比较紧张,我建议至少把这几类场景都亲手跑一遍:
- 输入是一位数,比如
5,看输出是不是5; - 输入是整十倍,比如
120,看循环会不会漏掉中间的0; - 输入一个比较大的数,比如
9876543210,确认累加结果在多语言下不溢出。
一个很实用的自检思路是口算一个简单数(比如123),然后对比程序输出。如果结果不对,优先检查累加器的位置、循环终止条件和整除符号这三处,绝大多数错误都出在这里。
说实话,这道二级真题的难度放在整个编程学习曲线里也就是个小土坡。但小土坡也有它存在的意义:它检验的是你有没有养成扎实的拆解思维和规范的做题习惯。从现在开始把“数位之和”这种基础题当成一回事,后面的路会稳很多。