ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

东方博宜OJ 1201-1210题解:循环与数组入门避坑指南

东方博宜OJ 1201-1210题解:循环与数组入门避坑指南 作为一个常年泡在各种OJ平台上的老选手我太知道“东方博宜OJ答案1201-1210”这个标题背后意味着什么了。这大概率是学校布置的编程作业卡在1201到1210这几道题上的同学多半正处在“循环还凑合、数组刚接触”的过渡期。东方博宜OJ的题目编号体系里1200段正好是从基础语法向简单算法思维爬坡的位置说难不难但思路没转过来的话每道题都能卡你好一阵。这篇博文我就以过来人的身份聊聊这10道题真正在考什么、每个题型的通用解法和提交时最容易被扣分的细节顺带把我自己刷题踩过的坑都翻出来讲一讲。1. 先看清全局东方博宜OJ 1201-1210到底在练什么1.1 题号范围与难度定位东方博宜OJ东方博宜在线评测系统是不少学校C语言、C程序设计课的指定练习平台题目编号是连续的整体难度也随着编号逐步抬升。1000段出头基本是顺序结构也就是“读入-计算-输出”一条路走到底1100段开始出现选择结构if-else才算真正进入编程逻辑到了1201-1210这一段各位可以把它理解成“循环结构加强版”和“一维数组敲门砖”的混合体。我翻了翻题库的大致分布1201-1210这10道题基本不会跳出几个大类数值处理、图形打印、数组统计、简单数论入门。个别题目可能还会串一点字符串的影子但核心还是循环和数组这两板斧。难度上是典型的“入门偏中”比前面的顺序结构题多了弯弯绕但也没有到递归、搜索那种需要天分的程度。只要把常见的几套模板吃透这10道题是可以稳定拿下的。这个定位很重要因为很多同学是第一次在OJ上感受到“这题我会读但不知道怎么写”。这种挫败感是很正常的不是笨是还没建立“把数学过程翻译成循环语句”的思维。我后面会把这层翻译过程拆开讲。1.2 十道题的高频考查点分布与其一道题一道题地给代码不如先把这段题目的“出题逻辑”摆出来。我根据自己的刷题经验把1201-1210这个抽样范围的常见题型整理成了下面这张表你们刷的时候可以对照着看自己卡在哪一类题型归类典型考点状态特征累加求和类for循环累加、奇数/偶数筛选、范围边界处理状态变量初始化是重点数字拆分与数位处理类数字逆序、数位统计、水仙花数判断核心是%和/的组合拳图形打印类直角三角形、正方形、空心图形嵌套循环 空格/符号的坐标控制数组统计类求n个数和、平均值、最值及其下标读入n后再开数组的固定套路经典数论入门类最大公约数、最小公倍数、质数判断模板固定背住就能拿分这类题被OJ大量采用的原因也很简单机器判题好实现边界测试容易构造且能区分“背会了”和“真懂了”。你写的程序不仅要算对一组数据还得对边界数据也健壮。这也是OJ和普通笔试填空题本质不同的地方。当你意识到这10道题其实就是在反复考上面五类模型时焦虑感会立刻下降一半。接下来就是逐个击破。2. 核心解题思路拆解循环、数组与格式输出的底层逻辑2.1 数字处理类题目的通用思维数字处理类题目是1201-1210的重头戏题面上可能千变万化但底层的操作就那几个。拿最经典的“水仙花数”来说三位数153要满足各位数字的立方和等于本身。如果不用循环你得手算三位数拆位一旦要求“输出所有水仙花数”或者“判断一个范围内有多少个水仙花数”就必须写循环了。拆位这件事靠的是取余和整除的组合。要拿到数字n的个位用n % 10要丢掉个位用n / 10。这个操作重复做就能把每一位都抠出来。我在做两位数逆序、三位数各个数位求和这类题时从来不用数学公式硬凑而是直接上while循环int n 123; while (n 0) { int digit n % 10; // 取当前个位 // 这里处理digit比如累加、统计 n / 10; // 丢掉个位 }这段模板能处理任意位数的数字拆分比固定写三次取模接地气得多。水仙花数、逆序数、数位之和全部是这一套的变体。还有一个容易忽略的点数字逆序时要去掉前导零比如1200逆过来是21而不是0021这就要在累加结果时注意只要用reverse reverse * 10 digit的方式构建前导零天然会被吞掉不用额外处理。具体到代码模板判断水仙花数是这样的#include iostream using namespace std; int main() { for (int i 100; i 999; i) { int a i / 100; // 百位 int b i / 10 % 10; // 十位 int c i % 10; // 个位 if (a*a*a b*b*b c*c*c i) { cout i endl; } } return 0; }你可能会问为什么要用整除加取余而不直接用字符串转字符再转数字。原因有二一是OJ题目的输入输出经常用纯整数交换用字符串反而容易在格式上出错二是拆位法的时间复杂度和空间复杂度都是最优的处理几百万个数也不怕。2.2 图形打印类题目的两大关键图形打印题是另一个高频考点空心正方形、等腰三角形、菱形都属于这一类。这类题的核心心法只有一句话外层循环控制行内层循环控制列把每个位置的输出条件想清楚。拿空心正方形来说假设边长为n。你要意识到每一行输出的内容取决于当前是第几行、第几列。第一行和最后一行要打印整条边中间行只在第一列和最后一列打印符号其余位置打印空格。把这个逻辑翻译成代码就是#include iostream using namespace std; int main() { int n; cin n; for (int i 1; i n; i) { for (int j 1; j n; j) { if (i 1 || i n || j 1 || j n) cout *; else cout ; } cout endl; } return 0; }图形题真正的坑不在循环本身而在“空格”和“换行”的位置。很多同学卡在等腰三角形上是因为没搞清楚前面要打多少个空格。规律其实很简单总共n行第i行前面需要打n-i个空格再打2*i-1个符号。列一个表格就清楚了行号 i前置空格数符号数1n-112n-233n-35n02n-1图形题的另一个偷懒技巧是先写好“内层循环输出什么”的判断再回头补空格。顺序不要反否则很容易出现符号位置对但空格数量不对的情况在OJ上会报“格式错误”。2.3 数组与统计类题目的三个固定动作数组题是1201-1210这段和前面题目最大的分水岭。前面都是“给个数算一算”到数组就是“给一批数先存起来再统一处理”。很多同学第一次接触数组时最容易犯的错误是读完一个数就立刻处理一个数等到题目要求“输出最大值和第二大值”时才发现数据早就丢了。所以数组类题目第一步永远是一样的先读n再开数组再用循环读入。比如“输入n个整数求平均值并统计高于平均分的人数”B方案一定是int n; cin n; int a[1005] {0}; int sum 0; for (int i 0; i n; i) { cin a[i]; sum a[i]; } double avg 1.0 * sum / n; int cnt 0; for (int i 0; i n; i) { if (a[i] avg) cnt; } cout cnt endl;这里面有几个细节值得反复强调。第一数组下标从0开始但题目描述里通常说“第1个数到第n个数”代码里循环变量从0到n-1千万不要顺手写成i n否则会越界访问本地可能不报错到了OJ就是莫名其妙的内存错误。第二求平均值时先用1.0 * sum把整数转成浮点数再除否则整数除法会直接把小数部分砍掉导致统计结果偏大或偏小。第三数组开大一点没毛病n最大可能就到1000你开个1005甚至10000都不亏但开小了就等着“运行错误”的红色刺眼提示吧。求最值及其下标的题也是这个套路但多一个“等号陷阱”。题目要求“输出第一次出现的位置”那你更新最大值的条件就写if (a[i] maxVal)如果题目要求“输出最后一次出现的位置”条件就要写成if (a[i] maxVal)。差一个等号答案就完全不同。经验之谈这种题在1201-1210里出现的概率非常高审题一定要看仔细。2.4 经典数论入门最大公约数与最小公倍数这类题看着高大上其实就是背诵模板。求最大公约数的标准解法是辗转相除法也叫欧几里得算法原理就是两个数的最大公约数等于较小数和两数之差的最大公约数用取模写出来更简洁int gcd(int a, int b) { while (b ! 0) { int temp b; b a % b; a temp; } return a; }这函数背下来用处极大因为后续的约分、最小公倍数、判断互质全都能复用它。最小公倍数就是两数乘积除以最大公约数。OJ里如果同时考两者多半会有一道“输入m和n输出它们的最大公约数和最小公倍数”的题代码量不大但完全能检验你函数封装和循环控制的功底。我见过不少同学在这类题上栽跟头原因不是算法不会而是看不懂题目里的“a和b都不为0”这个条件意味着什么。它其实就是在告诉你不用处理0的情况放心写。反过来如果题目没提到这个前提你就得自己加个判断否则b为0时a % b直接崩溃。3. 参考代码与实现细节从思路到能跑通3.1 C 参考模板集合既然题目是1201-1210我直接把这段高频考点的C参考代码模板整理出来你做题时先对照思路再参考实现。累加求和类模板比如“求1到n中所有奇数的和”#include iostream using namespace std; int main() { int n; cin n; int sum 0; for (int i 1; i n; i 2) { sum i; } cout sum endl; return 0; }注意这里循环变量i 2直接从1开始跳着走比每个数都判断一次奇数更高效代码也更短。如果题目要求偶数和那就从2开始。这一行i 2就是这类题的核心得分点。数组逆序输出模板比如“输入n个数逆序输出”#include iostream using namespace std; int main() { int n; cin n; int a[1005] {0}; for (int i 0; i n; i) { cin a[i]; } for (int i n - 1; i 0; i--) { cout a[i]; if (i 0) cout ; } cout endl; return 0; }输出部分我特意加了一个判断如果不是最后一个数才输出空格。这样能保证行尾不出现多余空格。OJ的判题程序对行尾空格通常不敏感但保不齐有的题目用了严格比对养成不留行尾空格的习惯能少踩一堆格式错误。最大公约数与最小公倍数组合模板#include iostream using namespace std; int gcd(int a, int b) { while (b ! 0) { int temp b; b a % b; a temp; } return a; } int main() { int a, b; cin a b; int g gcd(a, b); int l a / g * b; // 先除再乘防止溢出 cout g l endl; return 0; }a / g * b而不是a * b / g是因为两个int相乘可能溢出先除再乘能降低风险。虽然OJ入门题的数据范围一般不会大到爆int但这个写法的习惯值得养成。3.2 Python 对照写法与差异点如果你的学校用的是Python语言同样的思路也有对应的写法。Python代码更短但有两处和C差异很大必须单独说。第一处是输入解析。C用cin n可以连续读多个数Python则需要配合input().split()来切分字符串再转int。比如读入一行包含n个整数的写法n int(input()) a list(map(int, input().split()))第二处是循环边界。Python的range(1, n 1)会包左不包右所以想输出1到n的循环必须写n1逆序则用range(n - 1, -1, -1)中间的-1表示步长递减很多新手第一次看到这个写法都懵。求平均值的Python模板n int(input()) a list(map(int, input().split())) avg sum(a) / n cnt sum(1 for x in a if x avg) print(cnt)这份代码能过但前提是输入格式必须是“第一行是n第二行是n个空格分隔的数”。有些同学喜欢用input().split()先读第一行结果发现第一行只有一个n再读第二行就出错了。这个和C的流式读取逻辑不一样要特别留意。至于空心正方形Python版本的思路完全一样只是语法上把大括号换成了缩进不再赘述。3.3 提交OJ时的输入输出规范代码写对只是第一步能不能过判题系统是另一回事。OJ对提交行为的机械要求比想象中严格得多我列出几条最容易踩的规范第一条绝对不能写“请输入一个整数”这类提示语。OJ的输入管道是自动注入的你的提示语会混入输出数据里直接判错。本地调试无所谓的但提交前记得删掉所有cout 请输入...之类的行。第二条输出格式里的大小写、空格、换行都要精确匹配。尤其是“Case #1: xxx”这种输出格式冒号后面往往有个空格得完全照抄。一个稳妥的办法是从题目描述里复制输出示例把示例里的空格和换行原样保留到代码里。第三条使用标准输入输出而不是文件读写。虽然部分OJ支持文件重定向但东方博宜这类入门平台默认都是从键盘读、往屏幕输出不需要freopen也不会给你任何文件参数。写freopen(in.txt, r, stdin)反而可能导致本地能跑、OJ上读取不到数据。第四条留意题目要求的换行。有的题明确说明“每个结果占一行”那就在每次结果后输出endl有的题要求“两数之间用空格分隔”就不要多打换行。这些细节在题目描述里都有审题时用笔圈出来能省不少调试时间。4. 刷OJ必踩的5个坑与排查技巧实录4.1 编译错误CE最常见的三个原因编译错误是新手最常遇到的提示我第一次刷OJ的时候有一道题连续CE三次原因现在想想都觉得丢人。第一个原因是头文件写错比如把iostream写成iostream.h或者漏写#include。现在的OJ环境基本都是C11以上标准不带.h的后缀是统一规范有些旧教材里的写法可能本地能过提交就报错。第二个原因是main函数的返回类型标准写法是int main()并以return 0;结尾。偶尔看到有人写void main()这在某些编译器上能跑但在OJ的严格的GCC编译环境下通常会直接给出编译错误或者警告后判错。第三个原因是变量名和库函数冲突比如某道题要统计字符数量把变量命名为count这个没问题但如果你把变量命名为endl或者data在某些编译环境下就会和标准库的符号冲突。解决办法很简单取名字别偷懒用cnt、sum、num这类不会撞车的命名。4.2 答案错误WA的高效排查思路WAWrong Answer是比CE更让人揪心的提示因为它说明程序能跑只是结果不对。遇到WA我的第一反应不是重写而是构造边界测试数据。比如题目说n的取值范围是1到1000那就分别测试n等于1、n等于1000、n等于2这样的小边界。很多边界case会暴露逻辑漏洞比如求平均值的题n等于1时平均值就是它本身高于平均值的个数应该是0你的代码在这个输入下能跑对吗再比如循环边界写成i n的题当n等于最大值1000时数组下标会不会越界这些测试用例花不了几分钟却能帮你定位到绝大部分WA的元凶。还有一个排查技巧是输出中间变量。在关键计算位置加几行临时输出的代码本地跑一遍看中间结果是否符合手算结果。这比瞪着眼睛看代码高效得多。当然调试完记得把临时输出注释掉再提交否则输出多于预期照样WA。4.3 运行超时TLE与内存超限MLE的常见原因1201-1210这个段位的题理论上不该出现TLE毕竟数据规模都不大。万一真碰到了多半是写成了死循环。最常见的死循环写法是while循环里忘记更新循环变量。比如用while写累加求和while (i n)但循环体里没写i程序就永远卡在循环里出不来了。这个错误在本地调试时表现为程序无法结束提交后就是TLE。另一个隐蔽的性能损耗是用了不必要的双层循环。有的题明明可以用单个循环O(n)解决比如求最大值有人非得先排序再取首位导致复杂度升到O(n log n)虽然入门数据规模也能过但这不是好习惯。刷题阶段就建立“能一次遍历解决的就不要两次”的意识后面学算法会轻松很多。MLE内存超限在入门题里极其罕见但这不代表数组可以随便乱开。我见过有人开一个int a[1000005]来存根本用不到的数组这种写法虽然在这个段位不会出问题但养成滥开数组的习惯对后续刷题是有害的。合理评估数据范围够用就好。4.4 输出格式错误PE——最冤枉的扣分点PEPresentation Error是所有错误提示里最让人血压升高的因为程序逻辑全对就是输出格式不匹配。构图题的空格、行尾的空格、空行的数量都有可能触发PE。以图形打印为例菱形和三角形的每一行后面如果多打了一个空格一般不会被判错但第一行前面多打了一个空格或者两行之间多了一个空行就会被判PE。论坛上有个不成文的经验如果代码逻辑没问题却被判PE优先检查行尾空格和额外换行。我自己的习惯是手动模拟一遍样例输出逐字符比对。把题目样例输出复制到文本编辑器里再把我的程序输出粘贴过去对比差异。这个土办法虽然原始但非常有效。4.5 怎么善用OJ的判题反馈很多同学看到Red“WA”或者“CE”就慌其实OJ的判题反馈是最高效的debug导师。每种反馈都对应一类问题CE是语法层面WA是逻辑层面TLE是性能或死循环PE是格式问题RERuntime Error通常是数组越界或除零。RE在1201-1210里也偶有出现多半是数组越界访问。常见场景是题目要求输入n个数你开了数组a[100]但没注意n可能到1000。所以我在前面反复强调数组要开够就是这个原因。排错时不要盲目改代码先明确目标当前反馈是哪一类问题聚焦到对应的模块调试。我用这个习惯刷题效率至少翻了一倍。5. 关于“找答案”这件事我个人的真实体会聊到这一步我想把这些年在刷题社区里看到的、包括我自己经历过的经验都摆出来。很多人搜“东方博宜OJ答案1201-1210”是为了快速交差这个心情我完全理解毕竟课程作业有截止时间谁也不想卡在最后一天熬夜。但代码这东西有个特点复制粘贴的时间成本很低反噬却来得很快。你抄下来的代码在你遇到变体题时毫无用处。1201-1210是1200段的题目到了1300段、1400段题型会从单层循环进化到双重循环嵌套从数组遍历进化到字符数组和字符串处理这时候如果你没有真正理解1201-1210考你的循环和数组思维你会发现自己连题目都看不懂。这不是危言耸听是很多的真实经历。我给出的建议是先自己写一遍哪怕写得又臭又长、暴力得不得了只要能跑通就是胜利。写完之后再去搜题解把别人的代码和自己的代码对比重点看两点一是别人的循环边界怎么处理的二是别人有没有用更巧妙的数学规律。看懂之后再敲一遍这次敲出来的代码才算真正属于你的。最后分享我个人的一个小习惯每刷完一道题在代码文件顶部写三行注释记录题目编号、核心思路、踩过的坑。比如“1201-累加奇数和-注意循环i从1开始步长为2”。这个习惯坚持下来以后复习时会发现效率高得离谱比到处翻答案有用得多。1201-1210这10道题只是起点把这里的套路吃透后面你会感谢现在认真刷题不图省事的自己。提示任何OJ平台做题核心是独立思考后的“顿悟”代码只是思维的最终呈现。请务必在完成自己的尝试后再参考上述思路。
返回列表