ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

东华机试OJ进阶81题:算法刷题路线与考场实战指南

东华机试OJ进阶81题:算法刷题路线与考场实战指南 很多同学问我东华大学机试怎么准备我通常都会先让他们把手头那套“2023东华大学机试OJ进阶版1-81题”从头到尾过一遍。这套题不是入门题库而是很多保研生和考研复试党刷了都说“很有分量”的进阶题单覆盖的知识点很广难度也从基础语法一路延伸到了动态规划和图论。你能不能在机试里稳住心态、稳定输出很大程度上取决于这套题你刷得够不够透。这篇文章我就把这81道题当成一个整体来拆考什么、怎么刷、哪些题值得反复做、提交报错到底怎么查一条龙讲清楚。不管你是第一次碰OJ的萌新还是刷到一半卡在瓶颈期的选手都能在下面找到适合自己的阶段建议和实操方法。1. 题库背景与题型分布分析1.1 东华机试OJ进阶版1-81题到底是什么先解释一下“OJ”这个词。OJ全称是Online Judge在线评测系统简单说就是你把代码提交到网站上系统自动用一大堆测试数据跑你的程序然后告诉你“Accepted通过”或者“Wrong Answer答案错误”。东华大学的机试就是在这样的系统上完成的所以平时刷OJ的过程本质上就是在模拟真实考场。“2023东华大学机试OJ进阶版1-81题”是一套由浅入深的题目集题目编排很有逻辑。1到20题偏基础但比单纯练语法的入门题要难会考你字符串处理、简单模拟和基础数学21到50题开始进入算法核心区排序、二分、DFS、BFS、背包这类经典问题都会出现51到81题则是综合题经常把多个算法揉在一起是真正拉分的地方。很多同学刷到一半会觉得“怎么突然变难了”这其实不是你的问题而是题单设计上就有意设置了梯度前30题帮你找手感中间30题逼你掌握算法模板最后21题考验你灵活组合的能力。从实际机试结果来看能把这套题稳定做到60题以上的同学考场上基本不会出现“题目看得懂、代码写不出”的窘境。所以不管你目标是多少分这套题都应该作为核心训练材料。1.2 高频知识点与难度梯度速览根据我对这套题和同类机试题目的观察知识点分布大概可以归纳成下面这张表。注意这个比例是经验估算不是官方数据但用来指导刷题分配时间已经够用。知识板块预估题目数常见题型简单模拟与数学16题左右日期计算、进制转换、最大公约数、质数判断字符串处理12题左右单词翻转、子串统计、高精度运算排序与查找10题左右结构体排序、二分查找、第K大元素数据结构12题左右栈模拟、队列应用、链表反转、二叉树遍历搜索算法10题左右迷宫最短路径、连通块计数、全排列生成动态规划与贪心15题左右背包问题、最长上升子序列、区间调度图论基础6题左右最短路径、最小生成树、并查集从难度梯度上看1到20题是“给你一个明确的步骤你照着模拟就行”但要注意边界条件比如数组越界、除零、字符串末尾换行等21到50题需要你看出题目背后的算法模型比如“这题本质上是背包问题”51到81题则更看重综合设计可能一道题里既要排序又要二分还得加贪心。刷题的时候一定要清楚自己处在哪个阶段不要老拿后面的难题打击自己也不要一直在舒适区里转圈。2. 刷题路线与高效策略2.1 刷题前的准备语言、环境和常用头文件工欲善其事必先利其器。我建议机试语言优先选C原因很简单STL能帮你节省大量时间。vector、string、stack、queue、map这些容器在考试时直接调用比用C语言手写链表和哈希表快得多。如果你只会C语言也不是不行但至少要把qsort、字符串处理函数和手动模拟栈搞熟否则最后几道题会写得很痛苦。本地开发环境建议装一个轻量IDE比如Code::Blocks、Dev-C或者VS Code都行。关键是调试方便能打断点、看变量。不过要记住本地编译通过不代表OJ能过因为OJ的编译器版本、警告级别、运行环境都可能和你本地不一样所以平时就要养成“用标准C11语法”的习惯别用编译器特有的扩展语法。每次刷题前把下面这些头文件背到肌肉记忆里#include cstdio #include cstring #include iostream #include algorithm #include vector #include string #include queue #include stack #include map using namespace std;这是最常用的一套组合拳覆盖了绝大多数题目的需求。另外要熟练掌握两种输入方式一是固定组数输入比如先读一个n然后循环n次处理二是“读到文件结束为止”也就是while(cin x)或while(scanf(%d, x) ! EOF)。东华机试很多题目是多组测试数据如果你只写了一组数据的逻辑那几乎必WA。2.2 三阶段刷题法从专项到混合再到全真模拟我把81道题分成三个刷题阶段每个阶段目标不同方法也不同。第一阶段是“专项突破”对应1到30题。这一阶段按知识点分组刷比如今天专门做模拟题明天专门做字符串题。每做完一道题不要急着看题解先自己调实在卡了1小时再参考别人的代码。目标是建立条件反射看到“翻转字符串”能马上想到用双指针看到“日期相差多少天”能马上想到从公元1年开始累加的天数。第二阶段是“混合训练”对应31到60题。这时候不再按知识点分类而是随机抽题就像考试一样。拿到题目先不急着写代码花5分钟判断这题考的是什么有没有做过类似的题用什么复杂度可以过如果能在5分钟内定出思路这道题就成功了一半。这一阶段会强迫你把知识网络打通因为你没法靠“上一题是BFS”这种提示来作弊了。第三阶段是“全真模拟”对应61到81题。每套模拟题组控制在90到120分钟严格按考场规则来不能暂停不能翻笔记写完就交然后用剩余时间检查。这一步不是为了做对多少题而是训练考试节奏和心态。你会发现有些题不是不会做而是时间分配不对导致会写的题都没时间了。2.3 错题本到底应该记什么很多同学刷题就是“AC了就下一题WA了就改到AC为止”然后什么也没留下。这种刷法效率很低。我建议每道题都留个简单记录至少包含四个部分题目编号和一句话题意你的初始思路实际通过时用到的解法犯错原因。举个例子第37题给一个序列找最长连续上升子序列长度。 初始思路排序后比较相邻元素结果想复杂了。 正确解法一次遍历记录当前递增长度和最大长度。 错误原因没看清“连续”二字以为是求最长上升子序列。复习的时候只看错题本等于把最值钱的错题重新做了一遍。比从头再刷一遍所有题目的性价比高太多。3. 核心题型拆解与解题模板3.1 模拟与字符串高精度加法必须会模拟题是OJ的“送分题”吗不一定。模拟题的难点在于把题意翻译成代码翻译错了就直接WA。比如日期计算要处理闰年、月大月小稍微不细心就出错。我建议大家把常用的日期函数和进制转换函数提前封装好考场上直接调用。另一种几乎每年都考的字符串重点题是高精度加法。所谓高精度就是数字太大连long long都存不下只能用数组表示。核心思路是把数字的每一位拆开倒序放进整型数组然后按位相加、处理进位。下面这个模板非常实用#include cstdio #include cstring #include algorithm using namespace std; const int MAXN 1005; int a[MAXN], b[MAXN], c[MAXN]; char s1[MAXN], s2[MAXN]; int main() { while (scanf(%s%s, s1, s2) ! EOF) { int len1 strlen(s1), len2 strlen(s2); int n max(len1, len2); memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); memset(c, 0, sizeof(c)); for (int i 0; i len1; i) a[i] s1[len1 - 1 - i] - 0; for (int i 0; i len2; i) b[i] s2[len2 - 1 - i] - 0; int carry 0; for (int i 0; i n; i) { c[i] a[i] b[i] carry; carry c[i] / 10; c[i] % 10; } if (carry) { c[n] carry; n; } for (int i n - 1; i 0; i--) printf(%d, c[i]); printf(\n); } return 0; }注意三点数组倒序存储方便从低位开始加每轮处理进位carry要么是0要么是1最终输出前判断最高位有没有进位。这个模板在大多数OJ上都能直接过。字符串处理还有一个高频坑读入时把空白字符也读进去了。用scanf读字符串会自动跳过空格和换行但读单个字符或读带空格的一行时就要小心。建议处理带空格的行用gets老OJ或cin.getline然后手动遍历。3.2 搜索题BFS模板要刻进DNA搜索题在东华机试里比重不小尤其是BFS用来求最短步数、最少操作次数特别方便。BFS的标准套路是初始状态入队访问标记然后循环从队首取出状态尝试所有可能的下一步把合法的、没访问过的状态入队。很多同学写BFS容易漏掉“访问标记应该入队时就打上”这个细节结果同一个点被反复入队导致超时或死循环。给你一个可用的BFS模板以迷宫最短路径为例#include cstdio #include cstring #include queue using namespace std; const int MAXN 105; char maze[MAXN][MAXN]; int vis[MAXN][MAXN]; int dist[MAXN][MAXN]; // 距离/步数 int dir[4][2] {{1,0},{-1,0},{0,1},{0,-1}}; int n, m; int bfs(int sx, int sy, int ex, int ey) { memset(vis, 0, sizeof(vis)); memset(dist, 0, sizeof(dist)); queuepairint,int q; q.push(make_pair(sx, sy)); vis[sx][sy] 1; dist[sx][sy] 0; while (!q.empty()) { int x q.front().first; int y q.front().second; q.pop(); if (x ex y ey) return dist[x][y]; for (int i 0; i 4; i) { int nx x dir[i][0]; int ny y dir[i][1]; if (nx 0 || nx n || ny 0 || ny m) continue; if (maze[nx][ny] #) continue; if (vis[nx][ny]) continue; vis[nx][ny] 1; dist[nx][ny] dist[x][y] 1; q.push(make_pair(nx, ny)); } } return -1; // 无法到达 }重点留意方向数组dir定义成全局vis和dist可以分开也可以合并成一个二维数组记录从起点到每个点的最短长度初始化为-1即可。如果题目要求输出路径还要额外开一个pre数组记录前驱节点最后递归倒序输出。DFS的使用场景则更偏向于“求可行方案总数”“全排列”“连通块染色”。DFS递归时要特别注意递归出口和状态恢复也就是“回溯”。比如生成全排列每尝试一个数字后要恢复标记否则后面的分支会受影响。3.3 动态规划最长上升子序列和多阶段决策动态规划是进阶题的重头戏不懂DP后面20多题基本没法做。很多同学一听DP就头大其实可以把DP理解成“填表游戏”定义一个数组每个元素表示到当前位置为止的最优解然后通过状态转移方程一步步推下去。以最长上升子序列为例朴素做法是O(n^2)for (int i 0; i n; i) { dp[i] 1; for (int j 0; j i; j) { if (a[j] a[i] dp[j] 1 dp[i]) { dp[i] dp[j] 1; } } }但东华机试的题目n可能到达10万要求你用O(n log n)的贪心加二分优化。核心是维护一个数组dd[i]表示长度为i1的上升子序列的最小末尾元素。每次读入一个新数x就在d里二分查找第一个大于等于x的位置替换掉它。如果x比d中所有元素都大就追加到末尾。最终d的长度就是LIS长度。这个技巧在进阶题里出现频率很高建议自己手推一遍。除了LIS背包问题也是出题人最爱。01背包的经典转移是for (int i 1; i n; i) { for (int j V; j w[i]; j--) { dp[j] max(dp[j], dp[j - w[i]] v[i]); } }内层循环必须倒序才能保证每个物品只用一次。如果换成完全背包内层改为正序即可。我在第50题左右见过一道“多重背包”的题目其实只要把每种物品的数量按照二进制拆分成若干组再套01背包模板就行。这些东西你不提前练考场上很难在半小时内写对。3.4 图论并查集与最短路径不能丢图论题在81题里数量不算多但几乎每年都会有一两道而且往往不是最难的题却是最容易因为没模板而丢分的题。比如并查集代码量不大但思路很巧妙。模板记熟int find(int x) { return fa[x] x ? x : fa[x] find(fa[x]); } void unionSet(int x, int y) { int fx find(x), fy find(y); if (fx ! fy) fa[fx] fy; }使用前要把fa数组初始化成自己for (int i 1; i n; i) fa[i] i;。并查集常用来判断两个节点是否连通或者统计连通分量个数。如果题目要求维护集合大小再开一个size数组只在合并时更新根节点的大小即可。最短路径更不用说了Dijkstra是单源正权最短路的标准解。我用的是优先队列优化版本这里给大家一个精简模板#include queue #include vector #include cstring using namespace std; const int INF 0x3f3f3f3f; vectorpairint,int g[MAXN]; int dist[MAXN]; void dijkstra(int s) { memset(dist, 0x3f, sizeof(dist)); dist[s] 0; priority_queuepairint,int, vectorpairint,int , greaterpairint,int pq; pq.push(make_pair(0, s)); while (!pq.empty()) { int d pq.top().first, u pq.top().second; pq.pop(); if (d dist[u]) continue; for (int i 0; i g[u].size(); i) { int v g[u][i].first; int w g[u][i].second; if (dist[u] w dist[v]) { dist[v] dist[u] w; pq.push(make_pair(dist[v], v)); } } } }注意priority_queue默认是大根堆要加上greater得到小根堆pair排序先比较first所以first放距离second放节点。如果起点有多个可以加一个超级源点与所有起点连一条权值为0的边跑一次Dijkstra即可。4. 常见问题与排查技巧实录4.1 OJ提交常见错误对照表刷题过程中最让人烦躁的就是“明明本地跑得好好的提交就错”。我整理了东华OJ上最常见的几类反馈以及对应的排查方向希望对大家有帮助。提交反馈可能原因解决思路Compile Error少头文件、变量名冲突、语法错误看编译器给出的错误行号优先检查数组定义、语句结尾分号Runtime Error数组越界、除以零、栈溢出、空指针检查所有数组大小是否够、循环边界是否±1、递归深度是否过大Wrong Answer逻辑错误、边界条件漏判、精度问题造极端数据自测比如n1、最大值、全相同的数据Time Limit Exceeded算法复杂度过高、死循环估算复杂度考虑用二分、哈希或动态规划优化Memory Limit Exceeded数组开太大、递归栈太深、使用过多STL容器把全局数组改成动态分配减少无用容器这里重点说一下Runtime Error里的数组越界。很多同学定义数组大小是100但题目范围写到1000结果访问越界OJ直接报运行时错误而不是答案错误。我建议开数组时统一比题目上限多5到10个比如题目说n不超过1000就开1010。另外所有全局数组一定要初始化memset或循环赋值都行否则里面是随机值会引发各种诡异bug。4.2 输入输出陷阱样例过了却WA的迷之操作“样例过了但WA”是OJ新手最崩溃的场景。这里几乎都是输入输出或边界条件的问题。第一多组数据要循环处理直到EOF不要只跑一次。第二行末不能有多余空格。比如输出一行数组时数字用空格分隔算法是“前n-1个元素后面跟空格最后一个元素后面直接换行”。第三有的题目要求输出后不带任何多余空行但有些题目允许两个case之间有空行一定要看清题目描述。另外一个经典陷阱是读取字符时把换行符读进去了。比如你用scanf(%d, n)读入整数后再用scanf(%c, ch)读字符这时候ch很可能拿到的是缓冲区里的换行符。解决办法是在%c前加一个空格写成scanf( %c, ch)或者用getchar()把换行吃掉。这个小细节我见过太多人栽坑了。4.3 本地调试技巧造数据能力和打印大法调试OJ题和调试普通业务代码不太一样你不能打断点看堆栈更多时候只能靠“推理加打印”。我自己的调试习惯是先把题目给的所有样例都过了然后自己编几组“刁钻数据”测试。比如排序题我会测n0或n1的情况数字题我会测最大值int2147483647附近字符串题我会测含有空格、连续空格的输入。如果这些数据都能过基本就稳了。如果还是WA就在关键计算前后打印中间变量的值进入循环前打印数据更新答案后打印结果递归前后打印当前状态。但记得提交前要删掉这些调试输出否则会干扰评测导致WA或PE。也可以使用assert在代码里判断条件条件不成立时程序会直接崩溃但OJ上可能显示RE所以本地用assert提交前删掉。5. 考前冲刺与考场实战策略5.1 考前一周回归模板与错题本考前几天不建议再做大量新题。你可能会想“我是不是还有好多题没刷完”但我告诉你这时候刷新题容易增加焦虑而且短期也消化不了。正确做法是把之前整理过的错题本翻一遍把自己封装好的模板重新抄写一遍包括高精度、BFS、Dijkstra、并查集、01背包、LIS等。抄写不是浪费时间这能帮你把模板里的细节刻进记忆里。另外考前要熟悉OJ系统的提交方式。东华机试一般支持C、C、Java有的还支持Python。但同一个算法用不同语言运行效率差别很大。如果你主用C就一定要确认编译选项是否正确比如是否要求C11是否禁用gets函数等。考前一天可以在OJ上重新交一道简单题确认账号、密码、代码模板都没有问题这叫“轻装上阵”。5.2 考场上的时间分配与心态调整真正的机试一般2到3个小时题目数量差不多5到10道难度有梯度。我的策略是先把所有题都看一遍花5分钟评估每道题的难度然后从最简单的开始写。千万不要卡在第二题上死活不出来导致后面三题明明会做却没时间写。一般建议每道简单题控制在20分钟内中等题40分钟最后20分钟留出来检查。心态上如果遇到“完全没有思路”的题就把它放到最后先做其他题。做完所有能做的题之后再回来啃硬骨头。哪怕只能写个暴力解法拿到部分分数也比交白卷强。我记得有一次机试最后一题是动态规划我没想出最优转移方程但我用DFS枚举了一部分状态最后也拿到了一些分。机试不看过程但看的是你手头代码能跑出多少测试点所以暴力法在关键时候能救命。还有一点务必注意审题。东华机试的很多题目会带一些小限制比如“所有数都不重复”“结果对1000000007取模”“多组数据每组以一个0结束”。这些细节直接决定代码怎么写。我见过好几次整道题的思路完全正确就是因为漏掉了“取模”导致答案溢出最后全部WA。5.3 长期坚持与复盘价值把81题变成你的底气最后说点个人的真实体会。我当年刷这81题的时候其实一度刷到想吐尤其是50题之后几乎每题都要花一整个下午。但坚持到后期我发现自己的思维速度明显变快了很多题目刚读完题就能想到大致解法不是因为我聪明而是因为见过的套路足够多脑子里已经建立了“模式库”。比如看到“求满足条件的最短区间”你会想到滑动窗口看到“在一个有序数组里查找”你会想到二分看到“多源汇最短路”你会想到超级源点和反向建图。这些模式全靠刷题积累。等到真正上考场的那一刻你会感谢那个在OJ前反复修改、不断提交的自己。希望你也能把这81题刷明白让它们成为你机试的底气而不是压力。
返回列表