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,计算A+B并输出十六进制结果。例如输入1f和2a,输出49。多组输入直到EOF。
数据范围:字符串长度 ≤ 100000。
解题思路:看到100000的长度,首先排除把字符串转成int或long long计算的做法,数据范围直接爆掉。正确思路是模拟十进制加法的过程,只不过逢十六进一。十六进制每一位的字符和数值之间要建立映射,0-9对应0到9,A-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 ≤ 10000,M ≤ 100000,边权 ≤ 10000。
解题思路:这道题是图论里最经典的模板题,考的就是Dijkstra算法,而且因为数据范围到了10万条边,必须使用优先队列优化的版本。先想清楚为什么不能乱换算法:Floyd是O(N³),N=10000时直接不可能;朴素Dijkstra是O(N²),1亿次运算在三小时的总时间预算下也能过,但加上其他题目就有风险;Bellman-Ford是O(NM),10000乘100000等于10亿,直接把整场机试的时间烧光。所以优先队列Dijkstra是唯一稳的选择。
Dijkstra的核心思想是贪心:每次从未确定最短路的点里取出当前距离最小的点,用它的边去松弛邻居。优先队列负责维护“当前距离最小的点”,每次弹出时判断一下弹出的距离和dist数组中记录的距离是否一致,不一致说明这个点是旧数据,直接跳过。这就是堆优化的关键,省掉了遍历所有点找最小值的O(N)过程。
图用邻接表存储,vector<pair<int,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) { vector<vector<pair<int, 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}); } vector<long long> dist(n + 1, INF); priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long 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在极端数据下会溢出。第二,优先队列的greater<pair<long 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]会越界,还要额外处理边界,不如直接开n+1乘m+1的数组省事。
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_queue<int, vector<int>, greater<int>> 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; }复盘要点:这道题最容易翻车的点集中在优先队列的使用上。第一,greater<int>必须写在模板参数里,否则默认是最大堆,你取到的是最大的两堆,结果直接偏到天上。第二,每次合并前要检查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,千万不要漫无目的地改代码。先拿样例测一遍,如果样例能过,问题基本出在边界上,按这套顺序去排:
先检查数据范围边界,比如N=1、字符串为空、图只有一条边、数组下标为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两次,先停下键盘,去上个厕所或者喝口水,让脑子清空一下再回来调试。人在紧张状态下容易陷入“乱改循环”——改一个变量试一下、再改一个变量再试一下,这种操作只会浪费你仅有的三小时,而短暂休息往往能让你突然看穿那个藏在角落里的低级错误。祝大家都能顺利上岸,我们科大见。