☰
东华OJ基础题69-73全解析:数组、数字拆分与调试技巧
2026/10/3 0:15:34 网站建设 项目流程

说来也巧,每年到这个阶段,总有学弟学妹跑到我这儿问同一个问题:东华OJ的基础题刷到六十几题了,卡在69到73这一片,代码写了、样例也过了,一提交就是红红的WA,心态直接崩掉。我当年也是从这条路上趟过来的,所以今天专门写一篇把这五道题掰开揉碎聊一聊。不管你卡在哪一题、是C还是C++选手、甚至用Python刷,这份思路都适用。

先说清楚东华OJ是什么。它是东华大学在线的编程评测系统,题目按难度和专题排列,前面六十多题基本把输入输出、分支循环、数组字符串这些基础语法都过了一遍。做到69到73题这个位置,意味着你已经跨过了“能写代码”的门槛,开始进入“用代码解决具体问题”的阶段。这组题我不能把原题照抄出来,但可以负责任地讲,它们都属于一个典型专题——数组、数字处理和循环模拟的综合应用。这篇文章会用这五题的常见考法做样例,把每一类题的分析思路、代码写法和调试技巧全部分享出来。

1. 东华OJ基础题69-73:内容定位与考察方向

1.1 从题号安排看这组题的定位

东华OJ的题号顺序基本和知识点推进顺序一致。前面几题考顺序结构、简单计算,中间开始考分支和循环,到了60到70这个区间,数组正式登场。你可能已经注意到,从这附近开始,题面变长了,不再是一句话讲完“输入一个数输出一个数”,而是给你一段完整的场景描述,比如“输入n个整数,按要求处理后输出”。

69到73这五题在这个区间里扮演的角色很特殊。它们不是纯数组题,也不是纯数学题,而是把数组、循环、条件判断、数字拆分这些东西混在一起考。这正是OJ出题最喜欢的手法和真实场景下写代码最常遇到的情况——你很少会只用一个知识点解决一个完整问题。

我翻了一下自己做题时候的记录和跟别人对题目的讨论,这五题里出现过的知识点主要集中在这几个方面:从一行输入中读入多个整数并存入数组;对数组进行遍历、筛选、统计;把一个多位数拆成各个数位再重组;在循环里维护一个“当前最值”或者“累计结果”。这些东西单独拿出来你基本都会,但合在一起、再加上OJ严格的格式判定,就成了新手杀手。

1.2 基础题背后真正想考的东西

说实话,东华OJ这五道题本身的算法难度并不高,任何一道放到竞赛里都属于送分题。但为什么这么多人在这一片卡住?因为从这一组题开始,OJ不再考你“语法会不会”,而是考你“思路清不清楚、代码严不严谨”。

举个例子,数字拆分这类题,很多人第一反应是用字符串处理:读一个整数,转成字符串,再一位一位取。这个思路在本地跑完全没问题,但东华OJ这类题目的输入约定往往是“每行一个整数,可能包含多行”,而且数字范围是int范围内,字符串处理反而容易在格式和转换上出幺蛾子。更稳的做法是用除法和取余运算把每一位抠出来,这也是这一类题目默认的标准方法。

这五题集中训练的是三种能力。第一,把题目描述翻译成变量和操作的能力,比如“统计个位数为某个数的数字个数”这句话,你要能立刻想到用n % 10判断个位;第二,循环边界控制能力,比如“共T组数据”和“读到文件末尾EOF”是两种不同的输入方式,对应完全不同的循环写法;第三,输出格式的强迫症级严谨度,空格、换行、最后一个数后面要不要空格,这些细节直接决定你能不能AC。

2. 解题前的准备工作:读题、设计、复杂度估算

2.1 三遍读题法,样例不是摆设

我看到太多人做OJ题目的姿势不对:题目扫一眼,觉得看懂了,直接开写,写完拿样例跑一下,对了就交,错了就懵。这种做法在基础题阶段还能靠运气混过去,到了69-73这种综合题,十有八九要栽。

我自己的习惯是三遍读题法,这么多年带人刷题一直推荐给新手,反馈很好。

第一遍,快速浏览题面,只搞清楚三个问题:输入是什么、输出是什么、中间要做什么操作。这一遍不追求理解所有细节,但要能用自己的话把题目复述一遍。

第二遍,从头精读,重点关注约束条件和边界描述。比如“正整数”意味着你不用处理负数和零;“n不超过100”意味着你甚至可以用最暴力的方法;“如果不存在则输出-1”这种话就是典型的边界陷阱,很多人漏看的都是这种补丁说明。

第三遍,拿着样例手动模拟。把样例输入里的数据按你理解的流程在草稿纸上走一遍,看能不能得到样例输出。这一步是性价比最高的排查方式。你代码还没写,思路里的逻辑漏洞就已经暴露出来一大半。

我见过一个特别典型的例子:一道题要求“输出排序后的结果,每个数之间用一个空格隔开”,样例输出是1 2 3,看起来人畜无害。但提交后WA了十几次,最后发现题目在输出格式里写的是“行末不要有多余空格”,而他的代码在最后一个数后面也打了个空格。这就是样例不会告诉你、但评测系统一定会检查你的地方。

2.2 复杂度心里要有数

“这题我能不能暴力解”是每个刷OJ的人都问过的问题。答案是:看数据范围。东华OJ基础题的n通常非常小,几十到几百的量级,O(n²)的算法跑起来毫无压力。但这不代表你可以完全不顾算法效率,因为这一片题目里经常出现“多组输入”的情况。

比如一道题说“输入数据有多组,每组第一行为一个正整数n”,但没有告诉你一共有多少组。如果单组内你做的是O(n²)的冒泡排序,n只有100,那没问题;可如果题目没有明说n的范围,或者n能到10的5次方甚至更大,O(n²)就会超时。

我给新手的建议是写代码之前先花三十秒估算一下:最外层循环大概执行多少次、里面还有没有嵌套循环、总的计算量在什么量级。如果总量超过一亿次,就得思考能不能优化。基础题阶段你大概率用不到什么高级算法,但“用桶计数替代双重循环查找”这种技巧在数组统计类题目里非常常见,69-73这组题里就有类似的考法。

另外,别因为数据弱就放飞自我。养成计算复杂度的习惯,等到后面刷中档题的时候,你会感谢自己现在多花的这三十秒。

3. 核心知识点逐个击破

3.1 数字拆分与重组,基础中的基础

数字拆分是东华OJ从基础到进阶反复出现的知识点,69-73里基本一定会涉及。所谓数字拆分,就是给定一个整数,把它的个位、十位、百位……一位一位分离出来做处理。

标准做法是用取余和整除循环:

#include <stdio.h> int main() { int n; while (scanf("%d", &n) != EOF) { int sum = 0; while (n > 0) { sum += n % 10; // 取出当前最低位 n /= 10; // 去掉最低位 } printf("%d\n", sum); } return 0; }

这段代码做的事情很直观:n % 10拿到当前个位,n / 10把个位砍掉,循环直到n变成0。比如n=12345,过程就是取出5、4、3、2、1,最后sum=15。

实际操作中有三个细节容易翻车。第一,如果输入的n本身就是0,上面这个循环一次都不会执行,sum就是0,这个没问题。但如果题目要求“逆序输出数字”,n=0时你应该输出0而不是什么都不输出,这时候就要用do-while而不是while。第二,负数的取余在不同语言里行为不一样,C语言里-5 % 10结果是-5,所以如果题目里没说n是正整数,最好先把负数转成正数处理,或者用绝对值。第三,如果题目要求把拆出来的数位再重组,比如“把各位数字逆序排列后输出”,你要注意前导零的问题,比如1020逆序变成0201,输出的时候要不要保留0,完全取决于题目描述。

3.2 数组存值、统计与最值处理

到了69-73这组题,数组操作是躲不开的。常见的考法有这么几类:读入n个数存入数组,然后做某种筛选;或者直接不存数组,边读边处理。这两种思路的效率差别不大,但代码复杂度差别很大。

给你一个建议:需要“先全部读入再统一处理”的题,老老实实开数组存;可以“边读边算”的题,就别浪费内存。比如求一组数的最大值和次大值,其实不需要数组:

#include <stdio.h> int main() { int n, i, x; while (scanf("%d", &n) != EOF) { int max1 = -1, max2 = -1; // 假设数据都是非负数 for (i = 0; i < n; i++) { scanf("%d", &x); if (x > max1) { max2 = max1; max1 = x; } else if (x > max2) { max2 = x; } } printf("%d %d\n", max1, max2); } return 0; }

这段代码的巧妙之处在于只用两个变量就完成了最大值和次大值的维护。每一步更新的时候,如果当前数比最大值还大,原来的最大值就“降级”成次大值;如果当前数介于两者之间,只更新次大值。这个过程实际上就是一次遍历里同时维护两个排序状态,比“先存数组再排序再取前两个”的要快,而且不需要额外空间。

另一种高频考法是“统计类”,比如统计每个数字出现的次数。这种题最标准的解法是桶计数:开一个数组,下标当数字本身,数组值当次数。比如统计n个1到100之间的整数中每个数出现了几次:

int count[101] = {0}; for (int i = 0; i < n; i++) { scanf("%d", &x); count[x]++; }

这个思路之所以重要,是因为它在O(n)时间内完成了统计,而如果每次查询都去遍历原数组,复杂度就是O(n*m),数据稍大就会超时。桶计数的本质是用空间换时间,在数据范围有限的时候非常实用。

3.3 循环嵌套与多组输入的写法

东华OJ从基础题开始就很喜欢考“多组测试数据”,69-73也不例外。很多在这五题上翻车的人,问题不是出在业务逻辑上,而是连最外层输入循环的写法都没掌握。

最常见的两种输入模式你要烂熟于心。

第一种,题目明确说“第一行是一个整数T,表示测试数据的组数”,这种写起来最简单:

int T; scanf("%d", &T); while (T--) { // 处理一组数据 }

第二种,题目说“输入包含多组测试数据,处理到文件末尾”,这种要配合scanf的返回值来判断:

int n; while (scanf("%d", &n) != EOF) { // 处理一组数据 }

这里的关键是理解scanf的返回值:它返回成功读取的变量个数,读不到数据时返回EOF(即-1)。所以while (scanf(...) != EOF)的意思就是“只要能读到数据就一直处理”,这样就不需要用户手动输入一个终止标记。

还有一个非常常见的坑:多组数据之间,变量没有重置。比如求每组数据的和,如果你把sum定义在while循环外面,又没有在每组开始时清零,那第二组数据的和就会把第一组的结果累加进去,结果自然错得离谱。记住一条铁律:任何“每组数据独立”的变量,都要在循环体内部定义或者每轮循环开始前初始化。

4. 判题反馈与调试实录

4.1 常见判题结果到底在说什么

提交代码之后,OJ会返回一个判题结果。很多新手看到红字就慌,其实每一种结果的含义完全不同,排查方向也是天差地别。我按东华OJ常见的几种反馈给你列一张表。

判题结果含义重点排查方向
Accepted代码通过不用排查,做下一题
Wrong Answer答案错误算法逻辑、边界条件、输出格式
Runtime Error运行时错误数组越界、除零、递归过深
Time Limit Exceeded超时算法复杂度太高、死循环
Compile Error编译错误语法问题、头文件缺失、函数名拼写
Presentation Error格式错误空格、换行与要求不一致

这里我重点讲一下Presentation Error,因为这道题区间里太容易触发了。PE和WA的区别在于:你输出的内容在数值上是对的,但输出格式和题目要求不完全一致。比如多打了一个空格、少打了一个换行、行末多了个空格。

我当年带过一个学弟,一道“输出n个整数之和”的题,他犯的错是每组数据之间多打了一个空行。他自己看输出觉得“差不多”,但OJ不认识“差不多”,它拿你的输出和标准答案逐字符比对,一个字符不一样就是WA或者PE。所以写输出的时候,一定要跟题目要求的字节级格式对齐。

4.2 我是怎么定位“答案错误”的

WA是刷OJ路上最常见的反馈,也是新手最难解决的,因为OJ只告诉你“错了”,却不告诉你“哪里错了”。在处理69-73这几题时,我的排查套路已经固定下来了,你照做能省一大半时间。

第一步,重新读题。不是扫一眼,是精读。重点看三块:数据范围有没有限制(比如是否可能为0、负数)、输出格式有没有特殊要求(比如“行末无空格”、“每组数据后跟一个空行”)、有没有隐含条件(比如“按输入顺序输出”而不是“按从小到大输出”)。

第二步,自造边界测试数据。样例给的数据往往很温和,你要自己制造极端情况。比如n=1时能不能过?n=100且所有数都一样时能不能过?最小值和最大值出现时能不能过?我之前帮人调一道统计题,样例全过,但n=1时直接崩了,因为代码里假设了“至少有两个数”才去求次大值。这种问题只有边界测试能暴露出来。

第三步,打表调试。在关键位置加printf输出中间变量,把程序的实际执行过程“看”一遍:

printf("debug: i=%d, x=%d, max1=%d, max2=%d\n", i, x, max1, max2);

看完之后记得删掉这些调试代码,不然这些多余的输出会让你直接WA。

第四步,如果你的逻辑实在看不出破绽,重新审视“每轮循环变量重置”问题。这是多组输入题目里最隐蔽的坑。我自己的经验里,至少有三分之一帮别人排查的WA,最后都是“某个变量忘了清零”导致的。

4.3 提交前必查清单

我在东华OJ刷到后面养成了一个习惯,写完整段代码之后,先不急着交,按一份固定清单自查一遍。这套习惯帮我减少了很多无效提交。清单内容如下。

  • 数组开得够不够大:如果题目说n最大1000,就开1005而不是1000,留一点余量防越界。
  • 变量是否初始化:全局变量默认是0,但局部变量默认是随机值,局部变量不初始化是新手最常见的RE来源。
  • 循环条件是否正确:是i < n还是i <= n?是while (T--)还是while (T)?这种差一个字符的bug最难查。
  • scanf有没有加&:给int变量读值漏了&,在本地可能碰巧不崩,但在OJ上几乎必RE。
  • 输出格式是否逐字核对:空格、换行、冒号、逗号,全都要跟题目要求一致。
  • 多组数据的变量重置是否完成:每一轮循环开始时的状态是否干净。
  • int会不会溢出:如果累加结果可能超过21亿,就换成long long。

这套清单看起来都是小细节,但OJ就是这么不留情面,一个字符的差异就能让你的通过率从100%变0%。

5. 新手排错速查与避坑心得

5.1 高频问题对照表

把69-73这组题里我见过、以及我自己踩过的高频问题汇总一下,做成速查表,提交WA的时候拿出来对照,效率很高。

症状可能原因解决方案
样例能过,但提交WA边界条件没处理补测n=1、n=最大值、全同数据等边界
多组数据时答案越算越离谱累计变量没清零把sum、count等变量移到循环内定义
输出结果正确但格式被打回来行末空格或空行不匹配核对题目输出说明,最后一个数不打印空格
运行直接崩数组越界检查数组大小,确认下标从0还是从1开始
结果全是同一数值忘了读入新数据检查scanf是否写在了循环里面且每次执行
所有输出都比预期大一点多个样例累计没清空每轮处理前把结果变量重置为初始值

这里的每一条,都是我或者我带过的人真真切切踩过的。以前总觉得“这种低级错误怎么会犯”,真到OJ上熬夜调代码的时候才发现,低级错误反而是最消耗时间的。

5.2 几条专门讲给新手的经验

最后分享几条我刷东华OJ多年的经验,算不上什么高深技巧,但都是实战里反复验证过的。

第一,本地编译器能跑,不等于OJ能过。本地你的代码可能依赖了一个没有初始化的变量的“幸运值”,这在你的电脑上碰巧是0,在OJ的编译器上就成了随机数。所以写代码的时候别依赖任何未初始化的状态,老老实实把变量都赋值。

第二,代码能写出来之后,花一分钟手动推演一遍。这一步不能省,尤其是循环嵌套的题目。你把第一次循环、最后一次循环分别手动跑一遍,能抓住80%的边界问题。我教过的一个学生,每次写循环都会差一个数,后来我强制他每次写代码都推演首尾两次循环,这个问题基本绝迹。

第三,调试用的printf一定要删干净。这不是玩笑。有一次我调完代码忘记删调试输出,交上去WA,盯着判题结果发呆了十分钟才反应过来。建议把调试代码统一加一个特征标记,比如printf("DBG..."),最后全局搜索“DBG”一次清干净。

第四,如果你实在卡在一个题超过两小时,别硬扛。去洗把脸、走一走,或者换一道简单题做做,给自己二十分钟的缓冲。很多次我都是离开了屏幕再回来,突然想起“啊,那个数据可能是多组”,一下就解决了。卡题的时候最怕钻牛角尖,走出去反而能让大脑切换状态。

东华OJ基础题69-73这五道题,难点不在算法,而在“严谨”二字。数据怎么读、循环怎么控制、格式怎么输出、边界怎么防护,每一环都严丝合缝,才能换来一个绿色的Accepted。把这五道题吃透,你不仅是拿到了几道题的AC记录,更重要的是建立了面对OJ题目的系统化排查思维。这套思维往后做任何题目都用得上,包括后面那些真正的算法题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询