
2025年科大计算机复试的机试结束后备考群里的消息几乎都是这样的画风“第三题是不是图论我直接跳过了”、“第二题十六进制加法样例过了交上去还是WA”、“有没有完整题解我想把代码背下来明年用”。作为一个陪过好几届学弟学妹走完初试、机试、面试全流程的老油条我想把这套回忆版机试题目做一个系统复盘每道题都给出完整的解题思路和可以AC的参考代码再把我这些年看到的考场翻车案例一起写进去。这篇文章适用的读者很明确目标中科大计算机系的考研er、准备调剂到其他学校计算机专业的学生以及想了解985机试到底考什么、难度有多大的低年级同学。文章里的题目是按多位考生回忆还原的风格整理的不是官方原题数据范围也按历年机试的常见设定做了重建但考点分布和代码逻辑是实打实的完全可以用来当模拟题练。1. 2025中科大机试全貌与备考定位1.1 考试形式与场上环境的实际配置今年依旧是现场上机全程在线判题提交之后立刻能看见结果这一点和历年保持一致。机试整体时长大约三个小时题目数量多数考生反馈是6道左右难度阶梯非常明显前两道偏基础属于“认真读题就能拿分”的类型中间两道开始考数据结构与图论最后两道直接上强度区分度基本都出在这两道题上。编程语言方面C/C是绝对的主流选择。虽然部分题目用Java或者Python也能写但C在代码量、运行速度、模板成熟度上都有明显优势尤其当题目卡常数的时候Python的劣势会被放大。考场环境不用太担心一般会提供基础的文本编辑环境但别指望有太强的智能补全和调试体验平时练习就得刻意少依赖IDE养成“裸写代码”也能跑的习惯。提交策略上也要注意多数机试按最后一次有效提交算成绩所以不要抱着“交一版试试”的心态乱提交罚时和覆盖掉自己AC版本的结果都可能在总分上吃亏。1.2 考点分布与复习优先级把历年题目拉通看考点的集中度其实很高。我按今年考生反馈和既往真题风格整理了一张表优先级从高到低排列后面几个章节的题目基本也围绕这几个方向展开。考点分类典型考法出现频率备考优先级模拟与字符串日期计算、进制转换、大数加法、格式处理极高必拿分数据结构优先队列、栈、队列、并查集高必拿分图论最短路、最小生成树、BFS/DFS高核心拉分项动态规划线性DP、背包、LCS/LIS高核心拉分项数学基础GCD、素数筛、快速幂中性价比高这个分布不是偶然的。机试时间有限题目必须能在三小时内完成并稳定判题所以不会出那种思维难度极高但代码量小的偏题怪题反而更偏向“算法模板 边界处理 代码熟练度”的组合。换句话说练机试的核心不是刷难题而是把常用模板变成肌肉记忆同时训练自己在考场压力下写出没有低级错误的代码。1.3 机试真正想考察的底层能力很多第一次考机试的同学会误以为机试考的是“算法天赋”其实完全不是。三小时六道题每道题留给你的平均时间只有半小时这种时间压力下真正被筛选的是三个底层能力读题能力、调试能力、时间分配能力。读题能力体现在你能不能快速识别这道题属于哪个考点数据范围暗示了哪种算法。调试能力体现在WA之后能不能用几个边界用例迅速定位问题而不是干瞪眼乱改。时间分配能力则决定你能不能保证前四道题稳稳AC而不是在前两道简单题上死磕导致后面大题连读题时间都没有。我见过太多人拿着“题题都AC才算赢”的心态上考场结果前两道题反复重构最后两道题直接空白非常可惜。2. 真题复盘模拟与字符串处理附AC代码2.1 题1第n天是几月几号回忆版题目描述回忆版输入年份y和天数n输出y年第n天对应的日期格式为“yyyy-mm-dd”。需要正确处理闰年。例如输入 2025 60应输出 2025-03-01。多组输入直到EOF。数据范围y在int范围内n保证合法1 ≤ n ≤ 365或366。解题思路这道题考察的就是两个基本功——平闰年判断和月份天数打表。闰年规则是“四年一闰百年不闰四百年再闰”写成代码是y % 400 0 || (y % 4 0 y % 100 ! 0)。注意顺序别写反很多人把y % 100 ! 0写成y % 100 0样例过了但交上去就WA。有了闰年判断后用二维数组存平年和闰年的每月天数从1月开始逐月扣除n直到n不大于当前月天数为止。这里的边界判断要用n days[leap][month]而不是n days[leap][month]前者表示“还能继续跨月”后者会多扣一个月导致日期错乱。输出用%04d-%02d-%02d处理前导零月份不用置零重置因为逐月递增后自然就是正确月份。AC代码#include cstdio int isLeap(int y) { return (y % 400 0) || (y % 4 0 y % 100 ! 0); } int main() { int y, n; while (scanf(%d%d, y, n) 2) { int days[2][13] { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} }; int leap isLeap(y); int month 1; while (n days[leap][month]) { n - days[leap][month]; month; } printf(%04d-%02d-%02d\n, y, month, n); } return 0; }复盘要点这道题本身不难但踩坑点非常密集。第一是scanf返回值题目要求多组输入如果写成while (scanf(%d%d, y, n))而不核对 2输入结束时会因为返回EOF陷入死循环。第二是数组下标月份从1开始所以数组第0个元素要留着占位不然读天数时下标错位。第三是很多人忽略平年二月的28天直接用一套月份表跑遍所有年份。2.2 题2超长十六进制加法回忆版题目描述回忆版输入两个十六进制字符串A和B可能包含大写字母A-F和小写字母a-f长度可能达到100000计算AB并输出十六进制结果。例如输入1f和2a输出49。多组输入直到EOF。数据范围字符串长度 ≤ 100000。解题思路看到100000的长度首先排除把字符串转成int或long long计算的做法数据范围直接爆掉。正确思路是模拟十进制加法的过程只不过逢十六进一。十六进制每一位的字符和数值之间要建立映射0-9对应0到9A-F和a-f都对应10到15。输出时数字10到15要转回大写字符A-F。实现时有个常见的坑字符串读进来高位在前而加法要从低位开始算所以先把两个字符串反转从下标0开始逐步相加处理进位时用carry记录循环直到两个字符串都遍历完且carry为0。结果字符串也是低位在前的顺序所以最后要反转一次。前导零的处理尤其要小心加完之后如果最高位是0要循环剔除但至少要保留一位否则结果为0时会输出空串。AC代码#include iostream #include algorithm #include string using namespace std; int toVal(char c) { if (c 0 c 9) return c - 0; if (c A c F) return c - A 10; return c - a 10; } char toChar(int v) { return v 10 ? 0 v : A v - 10; } string addHex(const string a, const string b) { string s a, t b; reverse(s.begin(), s.end()); reverse(t.begin(), t.end()); string res; int carry 0, i 0; while (i (int)s.size() || i (int)t.size() || carry) { int sum carry; if (i (int)s.size()) sum toVal(s[i]); if (i (int)t.size()) sum toVal(t[i]); res.push_back(toChar(sum % 16)); carry sum / 16; i; } while (res.size() 1 res.back() 0) res.pop_back(); reverse(res.begin(), res.end()); return res; } int main() { string a, b; while (cin a b) { cout addHex(a, b) endl; } return 0; }复盘要点这道题最大的价值在于端正一个认知——机试里的“大数”不一定让你用模板库而是考察你有没有意识到基础类型的上限。看到100000长度的字符串第一反应必须是“模拟位运算”而不是“试试转long long”。另外注意大小写混合输入如果只处理了A-F不处理a-f你会在第七八个测试点上莫名其妙WA。2.3 模拟字符串题的通用踩坑点模拟和字符串是机试的送分主力但恰恰是送分题最容易翻车。我总结三个高频坑位都是真实发生过的事故。第一个坑是输入处理混乱。cin和scanf混用时如果输入里既有数字又有字符串很容易因为残留的换行符导致读入错位。我的建议是一道题里统一用 cin 或者统一用 scanf不要混合如果必须混合用getchar()吃掉缓冲区里的换行再读下一行。第二个坑是容器状态残留。多组输入时如果上一组数据的 vector、string 没有清空下一组数据会带着旧数据的尾巴一起处理结果自然错得一塌糊涂。写多组输入的代码时把容器的清空操作放在每组输入处理的起始位置而不是放在结尾这样逻辑更清晰。第三个坑是格式输出。日期题要求%02d十六进制题要求大写字母这些细节全部体现在样例里但很多人样例一眼带过根本不看输出格式要求。机试的判题就是全字匹配多一个空格、少一个前导零都是直接WA没有商量余地。3. 真题复盘图论与最短路径附AC代码3.1 题3单源最短路回忆版题目描述回忆版给定N个城市和M条双向道路每条道路有一个正整数长度。求从城市1到城市N的最短路径长度。如果城市1无法到达城市N输出-1。可能存在重边。多组输入直到EOF。数据范围N ≤ 10000M ≤ 100000边权 ≤ 10000。解题思路这道题是图论里最经典的模板题考的就是Dijkstra算法而且因为数据范围到了10万条边必须使用优先队列优化的版本。先想清楚为什么不能乱换算法Floyd是O(N³)N10000时直接不可能朴素Dijkstra是O(N²)1亿次运算在三小时的总时间预算下也能过但加上其他题目就有风险Bellman-Ford是O(NM)10000乘100000等于10亿直接把整场机试的时间烧光。所以优先队列Dijkstra是唯一稳的选择。Dijkstra的核心思想是贪心每次从未确定最短路的点里取出当前距离最小的点用它的边去松弛邻居。优先队列负责维护“当前距离最小的点”每次弹出时判断一下弹出的距离和dist数组中记录的距离是否一致不一致说明这个点是旧数据直接跳过。这就是堆优化的关键省掉了遍历所有点找最小值的O(N)过程。图用邻接表存储vectorpairint,int就够用。重边不用刻意处理因为松弛操作会自然取最小值。自环也不影响dijkstra更新条件dist[v] dist[u] w天然会忽略没意义的边。最后检查dist[N]是否还是无穷大是则输出-1。AC代码#include bits/stdc.h using namespace std; const long long INF 1e18; int main() { int n, m; while (scanf(%d%d, n, m) 2) { vectorvectorpairint, int g(n 1); for (int i 0; i m; i) { int u, v, w; scanf(%d%d%d, u, v, w); g[u].push_back({v, w}); g[v].push_back({u, w}); } vectorlong long dist(n 1, INF); priority_queuepairlong long, int, vectorpairlong long, int, greaterpairlong long, int pq; dist[1] 0; pq.push({0, 1}); while (!pq.empty()) { auto [d, u] pq.top(); pq.pop(); if (d dist[u]) continue; for (auto [v, w] : g[u]) { if (dist[v] dist[u] w) { dist[v] dist[u] w; pq.push({dist[v], v}); } } } printf(%lld\n, dist[n] INF ? -1 : dist[n]); } return 0; }复盘要点这份代码里有几个不写就会出事的细节。第一dist数组必须用long long边权10000路径可能经过很多条边int在极端数据下会溢出。第二优先队列的greaterpairlong long,int必须加省略会变成大顶堆贪心顺序直接反了。第三if (d dist[u]) continue必须写没有这行判断堆里的过期数据也会参与松弛虽然结果可能碰巧正确但代码不严谨遇到负权边甚至会死循环。3.2 为什么优先队列模板是考场首选如果你平时刷题用的是朴素Dijkstra上了考场遇到这数据范围基本只有两条路一是现场临时改堆优化手忙脚乱出错二是硬着头皮用朴素版祈祷数据不够卡。但机试不会给你祈祷的机会。我的建议是把优先队列版本当成唯一记忆的模板无论题目数据范围多大都先写这个版本。它的代码量只比朴素版多五六行但是能覆盖的题目范围大得多。那些劝你“先写朴素版过了就行”的人没考虑考场数据范围如果稍微大一点朴素版就是TLE的下场。把版本统一成堆优化之后你还可以省掉“看数据范围选算法”这个思考步骤把有限的脑力留给后面的难题。3.3 图论题考场避坑清单图论题的坑往往不在算法本身而在图和输入的处理上。第一是节点编号从1开始还是从0开始必须和题目描述对齐。这道题直接说了“城市1到城市N”所以所有vector分配n 1的大小下标从1开始用别在这种地方省空间导致越界。第二是M可能比较大scanf比cin快得多。当然如果使用cin前加了ios::sync_with_stdio(false); cin.tie(nullptr);倒也行但我个人在机试里默认用scanf省心。第三是重边。有些同学在存图时专门写个if (w mp[u][v])去重其实没必要。Dijkstra的松弛条件会自动选择最短的那条边你push几条边就多几次候选逻辑完全正确。强行去重反而容易因为代码复杂引入新bug。4. 真题复盘动态规划与贪心附AC代码4.1 题4最长公共子序列回忆版题目描述回忆版给定两个字符串A和B求它们的最长公共子序列长度。子序列不要求连续但要保持字符相对顺序。多组输入直到EOF每组两个字符串。数据范围字符串长度 ≤ 1000。解题思路最长公共子序列是线性DP的必修课递推式本身很简单但很多人只会背公式、不会推导。设dp[i][j]表示字符串A的前i个字符和B的前j个字符的最长公共子序列长度。当A[i-1] B[j-1]时说明最后一个字符可以配对子序列长度等于dp[i-1][j-1] 1。当两个字符不相等时当前公共子序列要么来自A的前i-1个字符和B的前j个字符要么来自A的前i个字符和B的前j-1个字符取两者的最大值。dp数组为什么要从1开始下标因为dp[0][j]和dp[i][0]都表示某个字符串为空时的公共子序列长度必须初始化为0。如果从0开始遍历转移的时候访问dp[i-1][j-1]会越界还要额外处理边界不如直接开n1乘m1的数组省事。AC代码#include bits/stdc.h using namespace std; int dp[1005][1005]; int main() { string a, b; while (cin a b) { int n a.size(), m b.size(); memset(dp, 0, sizeof(dp)); for (int i 1; i n; i) { for (int j 1; j m; j) { if (a[i - 1] b[j - 1]) { dp[i][j] dp[i - 1][j - 1] 1; } else { dp[i][j] max(dp[i - 1][j], dp[i][j - 1]); } } } printf(%d\n, dp[n][m]); } return 0; }复盘要点这道题有两个值得说的细节。第一memset针对的是整个dp数组所以每组数据开始前都要清空一次避免上一组数据残留否则长度计算会出错。第二很多人在遍历时习惯写for (int i 0; i n; i)然后里面写一堆if (i 0)的特判这是完全没必要的自讨苦吃。从1开始遍历让下标天然避开边界这是DP代码的通用习惯。4.2 题5合并果子最小代价回忆版题目描述回忆版有N堆果子每堆有一定重量每次合并任意两堆消耗的体力等于两堆重量之和。求把所有果子合并成一堆的最小总消耗。多组输入直到EOF。数据范围N ≤ 30000每堆重量 ≤ 10000。解题思路这道题换个名字叫“构造最优二叉树”也叫Huffman树。核心结论是每次选择重量最小的两堆合并得到的总体消耗最小。这个结论不需要在考场上严格证明但可以用一个直观的例子理解重量大的那堆越晚参与合并被累计加进结果的次数越少总消耗就越小。反过来如果一开始就把大堆合并了它的重量会反复出现在之后每次合并的消耗里代价翻倍。实现用优先队列小顶堆每次取最小两堆合并后把新堆重新入队循环直到只剩一堆。每次合并的代价累加到答案里。这里有个必须用long long的坑N最大30000重量最大10000总消耗在最坏情况下会超过int的21亿上限如果答题时用int测试点一卡就WA。AC代码#include bits/stdc.h using namespace std; int main() { int n; while (scanf(%d, n) 1) { priority_queueint, vectorint, greaterint pq; for (int i 0; i n; i) { int x; scanf(%d, x); pq.push(x); } long long ans 0; while (pq.size() 1) { int a pq.top(); pq.pop(); int b pq.top(); pq.pop(); int s a b; ans s; pq.push(s); } printf(%lld\n, ans); } return 0; }复盘要点这道题最容易翻车的点集中在优先队列的使用上。第一greaterint必须写在模板参数里否则默认是最大堆你取到的是最大的两堆结果直接偏到天上。第二每次合并前要检查pq.size() 1如果只剩一堆还继续循环pq.pop()会越界崩溃。这两个点都是代码层面的低级错误但考场上紧张起来就是会有人栽。4.3 DP与贪心的判别经验第五题是贪心第四题是DP很多同学会问考场上怎么快速判别一道题该用DP还是贪心我的经验是看局部最优选择是否会影响后续状态。合并果子每次选最小两堆选完之后的“新堆”和其他堆地位相同局部最优不会破坏全局最优的可能性所以贪心成立。LCS则不一样你当前字符配不配对会直接影响后面的匹配情况局部随便选一个最长路径最后可能错过全局更优解所以必须用DP枚举所有状态。一个更实用的判断标准是题目是否要求“你有多种选择每种选择会影响后续机会”。有后效性就是DP没有明显后效性且每一步有明确最优选择就是贪心。考场上如果拿不准优先考虑DP因为DP的暴力转移一般能保证正确性只是可能TLE而贪心一旦思路错了样例都可能过不了更浪费时间。5. 机试实战经验与常见故障排查5.1 考场最容易爆雷的五件事机试考的不只是你会不会算法很多时候是“你写出来的代码能不能过”。我在陪跑过程中总结过五个高频爆雷点几乎每年都有人栽在同样的地方。第一是数组大小开错。数据范围N ≤ 10000就有人开int g[10005][10005]直接内存爆炸。图论题用邻接表DP题开一维滚动数组或刚好够用的二维数组不要贪图方便开大矩阵然后MLE。第二是scanf返回值没检查多组输入的题在EOF时陷入死循环最后交上去等待你的不是WA而是TLE因为程序根本没退出。第三是变量名和库函数撞车比如有人定义一个变量叫time或y1在C环境下直接编译失败白白耽误时间。避坑的办法是用一些有前缀的变量名比如cnt、dist2、tmpY。第四是注释掉代码后忘了恢复这种操作通常发生在调试过程中你临时改了一行测试用的代码交之前忘了改回来。所以我每次提交前都会花30秒从头到尾扫一遍代码重点看有没有明显的测试残留。第五是“最后二十分钟重构”。这是我见过最多的翻车动作某道题写了一版能拿部分分觉得不够好决定推翻重写一个更优解法重新写的过程中时间耗尽连原本那版都没提交成功。在考场上的准则永远是能AC的代码才是好代码不要为了完美主义牺牲稳定性。5.2 从WA到AC的排查路线遇到WA千万不要漫无目的地改代码。先拿样例测一遍如果样例能过问题基本出在边界上按这套顺序去排先检查数据范围边界比如N1、字符串为空、图只有一条边、数组下标为0等情况。然后检查输出格式前导零、空格、换行、大小写全部逐字比对。再想输入是否有重边、自环、乱序等题目里没说但可能存在的脏数据确认代码对这些情况是否鲁棒。如果以上都排除了就要重新读一遍题确认自己有没有理解错题目意思比如“子序列”和“子串”的差别。TLE的排查路线不太一样通常不是bug而是算法复杂度超标。先确认有没有死循环再看这个复杂度是否需要换个算法。有些题可以用剪枝救回来但机试时间这么紧还不如直接考虑换思路。RE通常只有一个原因数组越界或者容器访问非法下标检查所有[i-1]、[v]这类下标访问尤其注意变量是否可能超出vector的size范围。5.3 常见问题速查表判题结果常见原因优先排查方向WA边界条件漏判、格式不符、理解错题意构造最小/最大边界用例逐字比对输出格式TLE算法超时、死循环、scanf使用不当检查循环跳出条件评估复杂度换更优算法RE数组越界、栈溢出、除零检查所有下标访问确认vector不超界MLE开数组过大改用邻接表、滚动数组、检查是否有不必要的缓存PE输出空格或换行位置不对逐字符比对样例输出格式很多同学在机房看到WA就慌其实机试的魅力就在于它是机器判题错因是客观且可以定位的。对照这个表一条条排查大多数问题都能在10分钟内解决关键是自己平时要养成这种调试习惯不要一上来就重写整个文件。5.4 把机试当靶机打方向别偏了备考群里最近有个风气不少人讨论“dc系列靶机如何打”觉得练习渗透找漏洞能锻炼机试能力。我的看法是趁早停手。机试考察的是在限定时间内、限定语言环境下用基础算法解决可复现的计算问题这和CTF靶机的漏洞挖掘、系统利用完全是两条路线。靶机训练能锻炼的是信息收集和工具操作对代码熟练度、算法模板、边界测试几乎没有帮助。把刷靶机的时间拿来多手写几遍Dijkstra上考场的收益要大得多。6. 机试结束之后复试面试与调剂预案6.1 机试成绩出来之后的复盘动作考完机试不等于整场复试结束。很多人出机房第一件事就是掏出手机对答案然后在群里争得面红耳赤。我建议克制一下考都考完了对答案既改变不了结果还影响后面面试的心态。真正要做的是当天复盘回忆自己哪些题是AC的、哪些题是WA的、WA大概卡在什么点上把这些写成文字。这不仅能给下届学弟学妹留素材也能让你在面试被问到“你在机试中遇到的最大困难”时有一个真实的素材可以讲。面试环节老师通常不问具体的刷题数而是问项目、问基础、问你对某个技术点的理解。机试里用过的图论模板、DP优化都是可以自然衔接到面试回答中的素材比如你可以在介绍自己做过的项目时提到“这里我用堆优化的Dijkstra做过一个路径规划模块”这种回答比干巴巴地说“我学过数据结构”有说服力得多。6.2 调剂视角上机能力在调剂中的分量如果初试或复试结果不如预期调剂是很多人最后的出路。调剂的时候机试能力不但没有浪费反而可能是你最硬的一张牌。多数调剂学校在复试环节会再次考察上机编程这时你的代码基础就派上用场了。更关键的是调剂联系导师时你如果能在邮件里附上一个GitHub仓库、几道算法题的提交记录、或者一个带着完整注释的代码笔记导师会立刻对你有直观的印象这比在邮件正文里写“我热爱编程”有用得多。调剂信息可以重点看目标学校研究生院官网、研招网调剂系统公告、往年调剂录取名单有条件的话联系在这个学校读研的学长学姐打听复试形式有针对性地准备机试。6.3 给下一届的备考时间线建议如果你正在准备下一年的科大计算机机试我的建议是初试结束后立刻开始不要等出分。每天写两到三道题就够了但必须保证是自己亲手AC的看题解看懂和自己写出来完全是两码事。机试前一个月把常考模板重新手写一遍尽量做到不看笔记也能把代码默写出来。写完之后试着用不同的数据范围跑几个边界用例养成“代码写完就自动查边界”的习惯。时间分配上也给大家一个参考前两个小时集中解决前四道题后一个小时只够做最后两道题的暴力分和检查前面代码。如果某道题想了30分钟还没有任何思路直接写一版暴力枚举拿部分分走人。机试从来不是要求满分而是要求你拿到尽可能多的分。我个人这些年陪跑下来最深的体会是考上科大计算机的人往往不是那些刷题最多或者脑子最灵光的人而是那些把模板写进肌肉记忆、把边界测试当成条件反射的同学。机试没有那么多神仙操作它更愿意奖励稳定、细心、务实的人。最后再分享一个小技巧考场上如果你的代码连续WA两次先停下键盘去上个厕所或者喝口水让脑子清空一下再回来调试。人在紧张状态下容易陷入“乱改循环”——改一个变量试一下、再改一个变量再试一下这种操作只会浪费你仅有的三小时而短暂休息往往能让你突然看穿那个藏在角落里的低级错误。祝大家都能顺利上岸我们科大见。