
刷题刷到第13题的时候很多人会突然卡住。不是题目变难了而是题变“活”了。前面十几道题基本在教语法输入两个数算个和判断个奇偶输出个三角形。到了13到15题这个区间OJ开始不跟你客气了——它不再问“你知不知道这个语法”而是问“你会不会用这个语法解决问题”。很多人在这一步开始怀疑自己其实不是你退步了是OJ题库的难度曲线在这里拐了个弯。这篇文章就从“OJ 13-15题”这个阶段切入聊聊这个节点到底在考什么、刷题的正确姿势是什么、遇到报错怎么查以及学校OJ和华为OJ这类企业评测平台在思路上有什么不同。不管你是正在大学OJ上赶作业还是打算认真刷题为求职机考做准备这个阶段都值得停下来想明白。1. 先搞懂OJ题目的编排逻辑为什么偏偏是13到15题这个位置1.1 大多数OJ题库的“三段式”难度曲线几乎每个OJ平台的前几十道题编排逻辑都惊人的相似热身题、语法题、思维题。热身题不用多说就是那种“输出Hello World”或者“读入两个整数输出和”的题目目的是让你跑通环境知道怎么提交代码、怎么看结果。大多数OJ的前5到10题都干这件事。接着是语法题。从第6题到第13题左右题目开始覆盖分支、循环、数组这些基础语法点。题目通常带有明显的提示词比如“如果……否则……”“重复N次”“输入N个数求最大值”看到这些词你基本能猜到该用什么结构。这个阶段的题本质上是在帮你把语法点一个个过一遍。到了第13到15题往后情况就变了。题目描述开始绕弯子不再直接把“用什么语法”写在脸上。比如前10题可能考“输入两个数输出较大的”但13到15题可能变成“输入一个正整数判断它是否为素数”或者“输入若干个数统计其中偶数的个数并输出它们的平均值”。看起来还是分支加循环但你需要自己做步骤拆解先做什么、再做什么、循环的条件是什么、边界要不要处理。这一步是从“照猫画虎”到“自己设计”的转折点也是新手最容易放弃的地方。1.2 第13到15题这个位置官方的“小心机”很多同学不知道OJ题目的顺序其实暗含了教学节奏。13到15题这个位置一般是第一轮语法学习的收尾也是第一次小测验的区间。你可以这样理解前12题在教“零件”13到15题开始让你“组装”。有些平台甚至会在题目顺序里故意插入一两道综合题把前面涉及的分支、循环、数组揉在一起。比如郑州轻工业大学的OJ、湘潭大学OJ早期题目都是这个节奏第13到15题通常涉及多层条件嵌套、双层循环或者一维数组的遍历和统计。有一个特别典型的信号从这一阶段开始题目里不再直接告诉你“请用if语句完成”而是给一段生活场景你需要自己判断该用什么结构。这种出题方式实际是在帮你建立“读题→抽象→建模→编码”的完整链路。后面所有难题包括华为OJ的机考考的都是这个链路而不是某个具体的语法。1.3 高校OJ和企业OJ的出题风格差异这里顺便说下很多人混淆的两个概念学校OJ和企业OJ。学校OJ的核心目标是把教学大纲里的知识点考明白所以题目往往短小、直接边界条件比较温和数据范围也不大。而像华为OJ这类企业评测平台题目会更偏向工程场景输入格式复杂、边界情况多、对时间和空间有要求。学校OJ允许你“差不多就行”企业OJ要求你“一个都不能漏”。所以我的建议很明确如果你还在学校OJ的第13到15题挣扎别急着去刷企业OJ。先在这个阶段把分支、循环、数组这些基本功夯实等你在学校OJ能稳定解决前30题再去看华为OJ你会发现很多题目其实只是换了一件马甲核心还是那些东西。2. 第13到15题的核心考点与原理不只是语法本身2.1 分支结构的“边界条件”才是真正的考点很多人写if语句很熟练但一到OJ上就错错在哪错在边界条件。第13到15题这个阶段分支结构的题目开始玩花样了。比如“判断某年是否为闰年”这个题看着简单但闰年的定义是“能被4整除但不能被100整除或者能被400整除”这个边界很多人第一次写都会漏。再比如“输入一个分数输出等级”90分以上是A80到89是B你会发现如果顺序写反了或者等号放错了结果就全乱了。我自己的体会是分支结构的核心不是语法而是“你把所有情况都列举全了没有”。有一个常用的检查方法——画一棵简单的决策树。比如判断闰年你先问“能被4整除吗”再问“能被100整除吗”最后问“能被400整除吗”每种情况走一遍看看你的代码能不能覆盖。我至今保留这个习惯无论是做OJ题还是写业务代码遇到分支逻辑我都会先在草稿纸上把情况列全再动手写。2.2 循环三种写法一个核心第13到15题几乎必考循环。循环的三种形式——for、while、do-while你知道区别吗很多人背过定义for适合知道循环次数的场景while适合不知道次数的场景do-while至少执行一次。但到了OJ题目里这个区分经常被模糊掉。比如“不断输入整数直到输入0为止”这种题用while很自然。但有些人习惯用for(;;)配合break也能做对。区别在哪里在于代码的可读性和你对循环控制的理解。我的建议是初期练习不要混用每种循环都刻意去用体会它们各自适合的场景。比如求1到n的和用for循环最直观读文件读到末尾用while是标准写法让用户输入密码直到正确用do-while可以减少一次多余的判断。另外循环里面有一个极其重要的概念叫“循环不变量”。这个名字听着吓人其实意思很简单在每次循环开始之前某个条件都是成立的。比如求累加和在每一次循环开始前sum变量都是“当前已经加完的部分的和”。写代码的时候如果每一轮循环结束后你都能说出“现在每个变量的状态是什么”那循环基本不会写错。2.3 数组下标越界是新手第一杀手到了第13到15题大概率会出现数组。比如“输入N个数输出最大值和最小值”这就要用数组存数据。数组的核心坑只有一个下标越界。C和C的数组下标从0开始很多新手习惯从1开始读数据最后赋值或访问的时候忘记减一直接越界。在OJ上越界不一定报错它可能让你读到内存里的垃圾值导致答案错误也可能直接Runtime Error。我处理数组问题的固定习惯是凡是涉及下标的地方写完之后手算一遍边界。比如开了一个长度为100的数组循环里写了i 100那最后一次访问的就是a[100]越界了。这个习惯一开始很费时间但刷到后面你会发现它真的能帮你省下大量的调试时间。另外数组初始化也是个高频错误。局部数组如果不初始化里面是随机值。每次定义数组后立刻初始化或者用memset清零可以规避一大批玄学错误。2.4 关于OJ答案能搜但不要“抄”热搜词里频繁出现“郑州轻工业大学OJ答案”“东方博宜OJ答案1168”这类搜索词我理解大家的焦虑。作业截止了题目不会做搜个答案应付过去谁都有过这种想法。但我想说句大实话如果你真的想靠刷题提升能力答案是最后的手段。搜答案的正确用法是先自己写卡住2小时以上搜到题解后只看思路不看代码。看完思路自己关掉网页重新写写不出来再回头看。这个过程看起来慢但一道题顶得上你抄十道题。以“东方博宜OJ答案1168”为例如果你搜到那个题目的题解你会发现核心就是一层循环加一个判断自己花点时间完全能推出来。真正卡住你的不是题目而是你还没养成把问题拆小的习惯。3. 实操完整走一遍第13到15题的解题流程3.1 先拿一道典型的“第13题风格”题目来拆解为了讲清楚完整的流程我构造一道非常典型的入门综合性题目这类题目在各大高校OJ的第13到15题区间几乎都能找到变体输入一个正整数N求1到N之间所有能被3整除但不能被5整除的数的和并输出。这道题有什么考点输入输出、分支同时满足两个整除条件、循环从1到N遍历、累加求和。恰好就是分支循环简单逻辑的组合和13到15题的定位完全一致。读题之后不要急着写代码。先做一道“手算”N20能被3整除的有3、6、9、12、15、18其中15能被5整除要排除所以和是369121848。这个手算结果非常重要后面要拿来和程序跑出来的结果对比。3.2 写代码先写出能跑的版本再谈优化很多人第一反应是写一个C语言版本用for循环从1遍历到N。这个思路没错C代码大概是这样的#include stdio.h int main() { int n; int sum 0; scanf(%d, n); for (int i 1; i n; i) { if (i % 3 0 i % 5 ! 0) { sum i; } } printf(%d\n, sum); return 0; }这个代码能过但我们要多想一步N的范围题目没有给。如果N很大比如10的9次方这个O(N)的遍历会超时。这时候可以用等差数列求和公式优化先求1到N所有能被3整除的数的和再减去其中能被15整除的数的和。能被3整除的数构成等差数列首项3末项不超过N且是3的倍数项数为N/3向下取整。#include stdio.h int main() { long long n; scanf(%lld, n); long long sum3 0, sum15 0; long long cnt3 n / 3; long long cnt15 n / 15; sum3 (3 cnt3 * 3) * cnt3 / 2; sum15 (15 cnt15 * 15) * cnt15 / 2; printf(%lld\n, sum3 - sum15); return 0; }这个版本里最容易被忽视的坑是把N定义成int。如果N能到10的9次方cnt3乘3再求和用int直接溢出OJ上就会Wrong Answer。所以看到题目没有明确给范围的时候直接用long long是稳妥选择。这也是我说“把边界条件想清楚”的典型例子。3.3 自查清单提交前花30秒过一遍代码写完了不要立刻提交。我有个提交前的固定自查流程分享给你第一步重新读一遍输入输出格式。题目说“输入正整数N”有没有说多组数据有没有说文件结束符EOF结束这些高频陷阱经常藏在描述的最后一行。第二步手算样例验证。把题目给的样例输入代入代码跑一遍看输出是否和样例一致。样例过了不代表能AC但样例都过不了就一定是错的。第三步想一组自己的边界测试。比如N1我们的程序应该输出0N15输出3691230注意15本身要被排除N取一个很大的数确认不会溢出。这些边界用例能帮你抓住大多数隐藏问题。第四步检查输出格式。OJ对空格、换行极其敏感。题目要求“输出一个整数”你就只输出一个整数加换行不要输出任何多余的提示信息。好多同学在本地调试时加了一堆printf调试信息提交时没删干净直接Presentation Error。3.4 从第13题到第15题三种常见的题目变体13题如果考的是分支14题往往就会考循环15题可能就是两者的综合。以我观察多个OJ的题库这个区间的常见变体有几种一种是“统计类”题目比如“统计字符串中数字字符的个数”这实际上是把字符串当作字符数组去遍历。另一种是“计算类”题目比如“求最大公约数和最小公倍数”这会用到辗转相除法。还有一种是“图形类”题目比如“输出N行的等腰三角形”这种题是对双重循环最好的练习——外层循环控制行数内层循环控制空格和星号的数量。图形类题目尤其值得认真做。很多人觉得输出三角形很幼稚但实际上它是理解嵌套循环的绝佳材料。一个等腰三角形你要同时控制三个量当前行数、该行的空格数、该行的星号数。我当初做这类题最大的心得是先像列一张表一样把行数、空格数、星号数列出来比如第1行有2个空格1个星号第2行有1个空格3个星号第3行有0个空格5个星号然后去观察空格式子和星号式子与行数的关系。公式推出来代码就是一层模板。4. OJ常见报错与排查技巧实录4.1 Wrong Answer优先怀疑边界而不是算法WAWrong Answer是OJ刷题中最让人抓狂的报错。代码跑到一半发现不对最大的错觉就是“我的思路应该没问题啊”。我总结的排查顺序是先查边界条件再查循环边界最后才是算法本身。因为算法层面的错误往往比较明显而边界错误是逻辑上“差一点”的错误。举个例子求斐波那契数列的第N项你写了for(i2; in; i),如果n等于1循环体压根不执行直接输出初始值f1看起来没问题但如果你初始值设置错了输出就是错的。这种题就要特别留意n0、n1、n2这几个小值。另外一个特别常见的WA来源是浮点数比较。如果题目要求“输出结果保留两位小数”你在中间过程用了浮点运算最后printf格式化输出看起来没问题。但有些题目要求判等比如“判断一个数是否为完全平方数”用sqrt(x) floor(sqrt(x))这种方式就会因为浮点精度出错正确做法是求根后取整再平方回去和原数比较。4.2 Runtime Error先看数组再看递归RERuntime Error通常意味着程序运行到一半崩溃了。最经典的元凶就是数组越界。前面提到的手算下标边界可以避开大部分问题。第二个元凶是除数为零或取模为零。比如求平均值时输入可能没有数判断奇偶时有人写了n % 2 0如果n是0这没问题但如果你写的是n % (x-1)而x又恰好等于1那就崩了。第三个元凶是递归没有退出条件或栈溢出。OJ平台对递归深度有限制如果题目数据范围稍微大一点深度递归就可能爆栈。看到RE先把数组开大再检查除零最后看递归这是标准处理顺序。4.3 Time Limit Exceeded这一步开始复杂度不再是可选项到了13到15题TLE超时一般还比较少。但如果你刷到20题以后TLE就会频繁出现。很多人第一次遇到TLE第一反应是“是不是服务器卡了”其实不是几乎都是算法复杂度太高。最典型的例子判断N是否为素数。新手喜欢从2试到N-1对N10的9次方就是10亿次判断必挂。稍微懂一点的人会只试到sqrt(N)复杂度直接降了几个量级。再进阶一步如果题目要求多次查询素数用埃拉托斯特尼筛法预处理比每次都现算快得多。在第13到15题这个阶段提前养成估算复杂度的习惯非常关键。题目的N是什么量级、你写的循环最多执行多少次、O(N)、O(NlogN)还是O(N^2)有没有优化空间这些问题在动手写之前就应该过一遍。别等代码写完了才回头优化。4.4 Presentation Error一个换行符都能卡死你PEPresentation Error被很多人当作“最可惜”的报错——答案几乎对了就是格式不对。但OJ不跟你讲情面。比较常见的格式陷阱包括多输出一个空格、输出结果之间没有换行、每行的末尾多了一个空格、最后多了一个空行。有些题目严格要求“每个数之间用空格分隔行末不得有多余空格”这种就要在循环里对最后一个元素单独处理。我这边的处理模板是在循环中判断如果当前下标是最后一个输出数字加换行否则输出数字加空格。虽然多写几行代码但不会再踩PE的坑。5. 从学校OJ到华为OJ不同平台的刷题策略5.1 高校OJ把作业题当成面试题来写很多人对学校OJ的态度是“过了就行”代码写得乱七八糟变量名是a、b、c函数没有逻辑全堆在main里。能过但白刷了。我的建议是从第13到15题开始就养成写“干净代码”的习惯。变量名见名知意比如用sum而不是s用cnt而不是c。一个函数只干一件事比如读入、计算、输出分开。提交前自己先读一遍代码看看如果别人拿到这段代码能不能一眼看懂。为什么要在学校OJ就养成这个习惯因为到了华为OJ这种企业级评测平台你写的每一行代码都会被考察到。华为OJ的题目往往更长场景更复杂数据规模更大你的第一版代码几乎不可能是最优解。如果你连代码规范都没养成写出来的东西自己都看不懂调试起来会非常吃力。5.2 华为OJ的考察重点工程化思维和边界处理华为OJ的热度这几年一直很高因为不少岗位招聘流程里有机考环节。从题目的角度看华为OJ和学校OJ有很明显的差异。第一是输入格式复杂。题目可能要求你从一行里读入若干个整数每个数之间用逗号分隔或者是读入一个字符串从中提取数字。这些在C语言里涉及字符串处理函数的运用比单纯scanf一个整数要费心得多。第二是边界条件刁钻。企业OJ的测试点里会包含大量边界情况比如数组为空、只有一个元素、元素值重复、数值达到最大值等。这一类测试点恰恰是学校OJ里比较少出现的。第三是“最优解”导向。学校OJ只要在时限内跑出来就行企业OJ因为数据规模大O(N^2)的算法几乎必挂。所以在华为OJ刷题必须先养成分析复杂度的习惯。我的策略是在准备企业OJ时以学校的第13到15题作为难度下限以简单到中等难度的算法题作为日常训练每道题都要求自己写出不止一种解法并对比它们的复杂度。这种训练方式坚持两三个星期机考的通过率会有非常明显的提升。5.3 刷题记录与复盘一篇有价值的刷题笔记长什么样很多人刷了100道题感觉什么也没留下。这就是缺复盘。我自己的刷题记录格式是题号、题目链接、考察知识点、我的解法思路、复杂度分析、WA或RE的原因、优化空间。第13到15题虽然简单但复盘照样有内容可写。比如我做“能被3整除不能被5整除”那道题就记录了三种解法暴力遍历、等差数列求和、容斥原理变体以及int溢出这个坑。两个月后回头看这篇笔记比很多教程都有价值。复盘还有一个意外的好处它能帮你看清自己的薄弱点。如果你连续三道题都因为数组越界报RE那你应该去专项练数组题如果连续几道题都在循环边界上翻车那就要回头把循环逻辑梳理一遍。这种基于数据的自我诊断比盲目刷题高效太多。还有一点我特别想说。很多人刷OJ的时候有个坏习惯做不出来就焦躁焦躁就去翻答案翻完答案觉得自己会了下次遇到类似的还是不会。这其实不是智商问题是缺少“卡住”的过程。做题卡住恰恰是进步最快的时候因为这时候你的大脑正在建立新的连接。我见过很多刷题进步神速的同学都有一个共同点愿意在一道题上死磕一两个小时死磕不出来再求助求助后一定自己重新写一遍。这种“先苦后甜”的节奏就是第13到15题阶段最该养成的习惯。如果你现在正卡在第13题或者第15题上别急着怀疑自己。这个位置的题目本来就是用来筛选“只是来试试”和“真的想学会”的人的。心态放平把每个报错当作一次排查练习把每道题当作一次复杂度训练刷完这个区间你的编程基本功就算真正打下了。接下来再往后刷你会发现自己看题的目光都不一样了。