凌晨一点半我盯着屏幕上那个红色的 Time Limit Exceeded叹了口气。这已经是今晚第四次提交失败了。备赛日常大概就是这样大部分时间你都在和超时、段错误、边界条件较劲偶尔AC几个题能高兴半天然后又得投入到下一轮刷题和复盘里。作为一个从零基础一路打到区域赛拿过奖牌的普通选手我想把这些日常记录下来——不是鸡汤而是实实在在的备赛方法、时间安排、踩过的坑和能直接用上的技巧。这篇内容适合正在为算法竞赛做准备的你也适合刚入门的编程新手。不管你是想在比赛中拿奖还是单纯想把编程功底打扎实这套备赛逻辑都值得参考。接下来我按备赛从头到尾的顺序把整个流程拆开讲。1. 备赛前的目标定位与整体规划1.1 先看清比赛规则再决定怎么练很多同学一上来就打开刷题网站埋头做题觉得“只要题刷得够多比赛自然就稳了”。这个想法不能说全错但效率很低。备赛的第一步其实不是刷题而是搞清楚你要打的比赛到底是什么规则。同样是算法竞赛规则不同训练重点和赛场策略完全不同。目前常见的竞赛形式大致分两类。一类是罚时制计分每道题只有通过和不通过两种状态通过题目数越多排名越靠前如果通过题数相同总罚时越少越靠前。每一道题第一次错误提交会计入罚时有些比赛还会对错误提交有额外等待时间。这种赛制下提交策略就很重要——不能看到有点思路就乱提交必须在本地把细节验证好再交。另一类是分值赛制根据通过的测试点数量或解题质量给分即使没写出正解暴力骗分也能拿到一部分分数。这种赛制下拿到“部分分”的意识和能力比死磕正解更关键。另一个需要看的是比赛时长和题量。比如一场三小时的个人赛通常有6到8道题一场五小时的组队赛可能有10到13道题。你需要根据这个规格来估计自己的读题速度、写题速度和调试速度再决定日常训练里一场模拟赛做多久、做几道题。怎么获取这些信息最靠谱的方法是找到官方发布的规则文档、往年题解和参赛者写的经验帖。把最近一两年的题目难度分布拉出来看一眼你会很清楚大部分题目集中在哪些知识点上。我当时备赛前花了整整一个晚上做这件事把每一年的题号、知识点、难度列了一张表后续的训练计划基本就是照着这张表来的。与其瞎猜不如先做几分钟的调研。1.2 分阶段备赛计划基础、强化、冲刺准备工作做完之后接下来要有一个可以执行的计划。我不推荐那种把每一天都排满的魔鬼计划因为备赛少则几周多则半年太紧的节奏很容易在中途崩掉。我更倾向于把备赛时间分成三个阶段基础期1-2个月目标是系统性地补完竞赛常用的基础算法和数据结构。这个阶段不要急着打模拟赛而是按专题刷题每个专题从入门题做到中等题保证自己真的理解了原理而不是背了代码。强化期1-2个月目标是专项突破和模拟训练。这个阶段开始做较完整的模拟赛也专门练习自己的薄弱环节。比如动态规划总是卡转移方程那就连续一周、每天只做动态规划的题直到看到一道题就能自动设计出状态。冲刺期最后3-4周目标是保持手感、稳住状态。这时候不再学新知识每天做一两道保持感觉的题周末打一场标准时长的模拟赛然后花大量时间复盘。赛前三天开始调整作息让大脑进入比赛的节奏。下面是一个我在基础期常用的周计划模板你可以按自己的时间调整工作日训练内容时长周一算法专题A概念学习3道入门题2小时周二算法专题A2道中等题整理模板2小时周三算法专题B概念学习3道入门题2小时周四算法专题B2道中等题整理模板2小时周五本周错题回顾 薄弱点补漏2小时周六半场模拟赛2小时4-5题2小时周日休息或只看题解不动手半天注意这个模板里每天的训练量并不夸张关键在于“持续”。备赛是一场长跑你不需要某天爆肝十小时第二天又什么都不做。两周之后你会发现哪怕每天只有两小时积累也很可观。计划还要留出20%左右的弹性因为学校里可能有课、有考试硬生生往里塞任务只会让你很快放弃。2. 核心技能训练算法与数据结构怎么练2.1 按专题刷题而不是按难度乱刷我刚开始刷题的时候特别容易犯一个错打开题库按通过率从低到高或者从高到低刷今天做一道字符串明天做一道图论后天再碰一道数论。这样刷了半个月题确实做了不少但遇到新题还是没思路。问题出在知识没有形成体系。竞赛算法其实是有固定几大模块的基本可以分成枚举模拟、二分与三分、前缀和与差分、贪心、动态规划、搜索DFS/BFS与剪枝、图论最短路、最小生成树、拓扑排序、数论gcd、素数筛、快速幂、同余、字符串哈希、KMP、Trie、数据结构栈、队列、优先队列、并查集、线段树等。每个专题的正确打开方式是先花半小时到一小时看懂基本概念和典型例题然后做三到五道入门题接着挑战两道中等题最后把自己对这类题的套路总结成模板和笔记。做完一个专题再做下一个专题知识点之间能够互相支撑后面复习时也会轻松很多。举个例子动态规划可能是很多人最怕的专题。其实它的核心就三件事状态怎么定义转移方程怎么写边界条件怎么初始化。我学背包问题时就是反复问自己当前这个物品选还是不选选了之后背包容量少了多少价值加了多少如果不选那和前一个状态有什么区别把这些用纸笔写清楚再去写代码就顺了。很多同学动态规划学不会是因为跳过了“手推状态”这一步直接照着别人的代码敲敲完也不知道为什么。2.2 模板库算法竞赛里的“作弊小抄”这里说的“作弊小抄”不是说赛场上违规而是指提前把自己的常用算法代码整理好可以在比赛时快速调用。正规比赛通常都允许选手携带纸质模板进入赛场有些比赛允许使用本地模板库但就算规则不允许整理模板的过程本身也是一种极好的复习。不过要注意模板千万不要直接从别人那里复制粘贴。必须要亲手敲一遍加上自己的注释理解里面每一行的作用。因为如果你不理解模板赛场上遇到需要改参数或修边界的情况你会无从下手。亲手整理的模板才是真正属于你的。比如二分查找看起来很简单但边界条件特别容易出错。我早期用的版本经常在区间长度为2的时候死循环。后来我固定用一种“左闭右开”的写法// 在有序数组 a 中查找第一个 x 的位置 // 返回下标如果不存在返回 n int lower_bound_pos(const vectorint a, int x) { int l 0, r a.size(); // 左闭右开 [l, r) while (l r) { int mid l (r - l) / 2; // 防溢出 if (a[mid] x) { l mid 1; } else { r mid; } } return l; }为什么用左闭右开因为这样mid在区间长度为2时mid会取到左端点配合l mid 1或r mid一定能缩小区间不会死循环。l (r - l) / 2而不是(l r) / 2是为了防止两个大整数相加溢出。这些注释看起来琐碎但到赛场上很可能就是救命的细节。模板库怎么分类我习惯按功能模块分文件夹比如“基础算法”“数据结构”“图论”“数论”“字符串”。每个文件里除了代码还有适用条件、复杂度和注意事项。例如在并查集模板里我会写上“路径压缩按秩合并复杂度接近O(α(n))不能用于删边场景”。这种提醒只有自己踩过坑才写得出来。2.3 学会估算复杂度不做“暴力出奇迹”的莽夫很多新手对复杂度没有概念觉得能跑出正确答案就行。但竞赛题的数据范围会直接决定你该用什么算法。看到一个题第一步应该根据数据范围反推期望复杂度而不是立刻上手写代码。举几个常见的对应关系。如果 n 不超过 10那可以考虑状态压缩枚举O(2^n) 或者 O(n!) 在 10的规模下没问题如果 n 在 10^5 左右O(n^2) 基本会超时至少需要 O(n log n) 或者 O(n)如果 n 达到 10^9那题目大概率考察的是数学推导、O(log n) 的二分或快速幂。养成每次读完题先写一句“n10^5需要O(n log n)”的习惯会帮你省掉大量因选错算法而导致的重写时间。除了复杂度还要熟悉常用数据结构的基本操作复杂度。比如优先队列的push和pop是O(log n)排序是O(n log n)哈希表平均O(1)但最坏可能退化并查集接近O(1)。这些知识点不需要背得很细但要能形成直觉毕竟赛场上的时间非常宝贵。我还记得有一次模拟赛我花了四十分钟写了一个暴力的排列枚举然后发现数据范围是10^5根本不可能通过。其实这道题就是一个贪心排序只需要O(n log n)。当时如果我先估算复杂度就不会浪费时间。从那以后我把“先看数据范围再想算法”写在了模板库的首页每次训练前都会看一眼。3. 日常训练的具体执行一份典型备赛日的时间线3.1 上午理论补漏与模板维护备赛日不一定非要从早上开始但我会建议你把每天最清醒的两小时留给最难的内容。我自己的日程是早上先看算法书或者高质量题解把最近做错的、没搞懂的知识点拿出来重新学一遍。这个环节不是“看小说”而是要动手验证。比如看到一个关于线段树的写法我会在编辑器里敲一遍把每个区间递归的参数写清楚然后思考pushup和pushdown究竟做了什么。上午还适合更新模板库。每学完一个算法或者从题解里发现一种更简洁的写法就把它整理进模板文件夹同时删掉旧版本。整理的时候一定写上说明比如这个版本有什么优势使用场景是什么注意事项是什么。以后冲刺期翻起来你会感谢当时认真写注释的自己。这里有一个小技巧不要只整理“正解模板”还可以整理“常见错误模板”。也就是说把自己常犯的错写成一份清单比如“数组下标从0还是从1开始”“开long long了吗”“多组样例是否重置了全局变量”。每次比赛前快速过一遍这些易错点能帮你在实际比赛时少交几次罚时。3.2 下午模拟赛模拟的是状态不只是题目模拟赛是备赛日常里最核心的环节。但很多人把模拟赛做成了普通刷题——边写边查题解中途还出去吃个饭时间到了也不停。这其实是在自我欺骗。模拟赛的意义并不是练那几道题而是练你在比赛压力下的时间分配、心态控制和手感。我一般会这样安排一场模拟赛严格按正式比赛时长来设闹钟比如三小时拿一套往年题目或者难度相近的题目一开始就进入比赛状态。期间不看题解、不查资料、不接电话尽量还原赛场环境。比赛的前十分钟只读题不写代码把每道题的难度、题目类型、预估做法写在草稿纸上然后挑一道自己最有把握的题先AC。比赛过程中如果一道题想了二十分钟还没有任何思路我会立刻标记出来先去做其他题绝不在一棵树上吊死。每写完一道题先检查数组越界、变量类型、输入输出格式再提交。模拟赛结束后先别急着看排名趁热打铁把没做出来的题补完这个过程比比赛本身收获更大。补题时要认真读题解弄清楚“我为什么没想到”而不是仅仅把代码抄一遍。补完题之后再用自己的话把整道题的思路讲一遍只有能给别人讲明白才说明真的会了。我还建议每次模拟赛都记录一个简单的日志哪道题花了多久、哪道题卡住了、卡的原因是什么、最终AC没有。坚持记录几周你会看到自己的时间分配在慢慢变好也能找出那些反复卡住你的题型。3.3 晚上复盘与错题本让每天的题没白刷晚上是我觉得最重要的一段时间因为备赛中最容易忽略的环节就是复盘。很多人的训练量很大刷了几百道题但水平停滞不前原因就是只做不复盘错过的知识点没有进入长期记忆。我的复盘流程可以简化成四步。第一步重述题目不看原题用一两句话把题目要求和约束条件说出来。如果说不清楚说明题目还没真正读懂。第二步卡点分析回忆自己在哪个环节卡住了是读题漏了条件还是某个知识点不熟或者根本没想到要用某个算法。第三步正解推导对照题解把正确做法从第一步到第十步完整地推一遍并在关键位置停下来问自己为什么这里要这样处理。第四步总结套路把这道题归到某个专题下总结一句“以后遇到什么特征就优先考虑什么算法”写进错题本。错题本不需要很精美但要有结构。我会把它分成四个类型读题失误、边界错误、复杂度选错、算法不熟。每周日把这周的错题全部过一遍把连续出现两次以上的问题标红那就是你下一周最需要弥补的地方。很多同学到冲刺期不知道该刷什么题其实就是因为没有错题本可以参考。有了它你的弱点一目了然。4. 团队配合与资源整理4.1 组队赛里怎样分工才能不是“三个人一起卡一道题”如果你参加的是组队赛那么一个常见的问题是三个人围着一道题讨论半天结果其他题目都没时间做。这其实不是能力问题是缺乏分工策略。组队赛赛场上读题结束后三个人应该快速标记自己最有把握的题。比如A同学擅长图论看到一道最短路题立刻举手说“这题我来”B同学擅长动态规划于是包下背包和区间DPC同学擅长字符串就把KMP和哈希相关的题接走。每个人先去把能拿的题拿下来而不是三个人盯着最难的那一道较劲。剩下的难题等已有题目AC之后再集合全队力量攻克。两个人同时写同一道题的情况要尽量避免除非是在交流思路阶段。如果一个人卡了很久另一个人可以把题目拿过去看一眼从不同的角度分析。平时训练时也要多打配合赛固定好队内的命名习惯、提交顺序和沟通语言。比如约定“我说‘稳了’代表样例过了但感觉没错位我说‘检查完了’代表准备提交”这种细节能在紧张的时候减少无效沟通。不过要提醒一点分工不等于偏科。组队赛里你可以有所侧重但每个人至少要会基础算法和中等难度题的操作否则一旦队友负责的题型被出到了难题全队的推进速度就会卡住。我见过不少队伍因为三个人都只会做某一种题型碰到变化题就集体沉默。因此平时除了按强项分工每周也要安排时间补一补自己的弱项。4.2 共享知识库把三个人的脑洞合成一个档案馆组队备赛最有价值的东西不是某一个人的模板而是三个人共同维护的知识库。我们当时用在线文档建了一个共享库分三块模板库、题解库和易错清单。模板库里放每个队员整理核心算法题解库里放每道模拟赛题目的思路和代码易错清单里记录我们三个各自常犯的低级错误。知识库的价值在于积累和复用。比如遇到一道题你觉得解法不常见把它的核心思路写进题解库下次队友遇到同类题时可以直接参考。又比如你的队友在一道题上犯了一个关于取模运算符号的错把这个教训写进易错清单比赛前翻一遍整个队伍都能避开这个坑。在整理共享知识库时我建议每个人都用自己的话写不要直接复制网上的长篇解析。写得简短不要紧但一定要是自己理解的产物。如果队友看不懂你写的东西那说明你自己也没完全搞懂需要再讨论一次。这个互相提问的过程其实是效率最高的学习。4.3 不只是代码比赛环境也得提前适应很多同学平时在自己电脑上写代码很顺一到比赛就各种不适应因为环境变了。所以赛前一两周一定要抽几次模拟赛在正式比赛系统或相近的在线评测平台上进行熟悉提交页面、错误反馈格式和编译器版本。提前准备的东西包括快速输入输出模板、常用代码片段、对拍脚本和打印版模板。所谓对拍就是用暴力程序作为标准答案和你的优化算法在随机数据上做对比从而找出优化算法中的逻辑错误。我常用的对拍脚本是这样的# 对拍脚本随机数据生成器 暴力程序 优化程序 #!/bin/bash for i in $(seq 1 100); do python3 gen_data.py in.txt python3 brute_force.py in.txt out_brute.txt python3 optimized.py in.txt out_opt.txt if diff out_brute.txt out_opt.txt /dev/null; then echo Test $i: OK else echo Test $i: WA break fi done对拍在调试阶段几乎是神器。当你用一个看似正确的算法一遍遍提交都WA时写一个暴力版本去做对拍往往几分钟就能找出错误样例。当然暴力版本只有在数据范围小的时候才可用它只用来验证逻辑不是用来提交的。比赛环境方面的小东西也别忘了备好纸质模板、证件、水、一点补充能量的零食。赛场上很多队伍因为没吃早饭到后半程脑子发懵。别把这当成小事体力也是实力的一部分。5. 常见问题与避坑指南那些让我多交了N次罚时的教训5.1 初期最容易犯的几个错我接触过很多备赛初期的同学发现大家的错误往往出奇地一致。首先就是刷题顺序乱今天觉得二维数组题有意思就去刷明天又去碰动态规划完全不按体系来最后每个专题都是半吊子。其次是卡题后缺乏思考时限有人可能一道题想了五分钟就翻题解看完觉得“原来这么简单”但下次碰到变式还是不会。再有就是只刷题不复盘做过两百道题但问你“这周学了哪三个新套路”一个都说不上来。针对这几个问题我的建议是第一给自己定一个明确的专题顺序按顺序推进第二给自己设一个“思考时限”比如简单题十五分钟没有思路可以看题解中等题二十分钟难题三十分钟超时再看题解不丢人但没有思考就看题解才是最大的浪费时间第三每AC一道题就在错题本或刷题记录里写一句话总结这道题的关键套路或易错点。哪怕只有一句话积累起来就是你的“算法直觉素材库”。5.2 赛前一周应该做减法而不是加法到了赛前最后一周很多人会突然焦虑觉得这个算法还没复习那个模板还不够好于是疯狂刷难题。我个人的经验恰恰相反赛前一周的任务是做减法。不要再学全新的算法因为你既没有时间消化也没有机会在比赛中灵活运用。与其学一个新东西导致头脑混乱不如把已经会的内容练到滚瓜烂熟。每天做一到两道中等难度题保持手感即可题目量不要大。重点应该放在三件事上一是过一遍自己的模板库和易错清单二是调整作息把睡觉和起床时间调整到比赛当天需要的节奏三是提前准备好比赛要带的物品包括打印好的模板、证件、笔、水、能量补给。赛前一天不建议再打完整模拟赛了。最多快速浏览几道题保持题感剩下的时间用来放松看看自己整理的笔记。紧张是正常的但过度紧张会让大脑在赛场上短路。我每次赛前都会提醒自己到了这个阶段实力基本已经定型比赛拼的就是把你的水平正常发挥出来。5.3 现场比赛稳住节奏的三个实用技巧赛场上的时间管理和平时训练有很多不同。我总结出三个技巧屡试不爽。第一个技巧是前十分钟只读题。把所有的题都读过一遍按难度和把握程度排序心里有一个大概的计划。然后先做自己最有把握的题保证第一道AC尽早出现。第一道AC不仅增加信心还会让后面读题写码都更放松。第二个技巧是卡题超过二十分钟立刻换。这个时间阈值可以根据比赛时长调整但核心逻辑是不要在一个点死磕。换个角度也许做完整道简单题再回来看思路一下就通了。如果所有题都卡住就回到最简单的暴力先拿部分分或稳住某个题的提交再逐步优化。第三个技巧是提交前检查六项有没有留下调试输出数组大小是否够变量类型是否需要long long边界条件是否覆盖多组数据是否清空了全局变量输入输出格式是否符合题目。我见过太多人因为少了一个return 0或者大小写写错而白交一发罚时。比赛里每一发罚时都可能在最后排名中成为致命差距。把这份检查清单放在模板里提交前对照一眼成本极低收益很大。6. 心态调整与长期坚持6.1 瓶颈期刷了多少题都不涨分怎么办备赛到一定阶段几乎每个人都会遇到瓶颈期模拟赛成绩总是波动在同一个区间该会的题好像都会但一比赛就排名上不去。这时候最忌讳的是加大强度、疯狂刷题。很多时候瓶颈不是“题刷得不够多”而是知识体系有隐藏的缺口或者是对某些套路的理解停留在表面。我突破瓶颈的办法是“降维打击”把刷题量减半把原先刷过的中等难度题重新做一遍但这次要求自己不看题解尽量用多种做法完成并且给同伴讲清楚每个做法为什么成立。这个过程会逼着你把“模糊的理解”变成“精确的理解”。另一个有效方法是参与讲解和讨论给别人讲题的过程会让你发现很多自己以为懂但其实经不起追问的地方。组队备赛的同学尤其适合这个方法。瓶颈期还有一个常见原因是心态着急。成绩不动不代表没有进步可能只是其他选手也在进步排名自然难以提升。这时候把注意力从“排名”移回到“今天我有没有比昨天少犯一个错误”状态反而会回来。我在冲刺期每周只关注错题本上标红的条目减少了多少只要减少就是进步。6.2 备赛是一场马拉松身体和热情都要管好这段备赛日记写到后面我想说一件容易被忽略的事身体状态和情绪状态。每次模拟赛一坐就是两三个小时长期下来颈椎、眼睛、手腕都会抗议。我自己大二那年备赛最疯狂的时候一天刷题超过十小时结果肩颈疼到去医院停了两天训练状态反而更差。后来我养成了一个习惯每刷题四十分钟就站起来活动五分钟每天跳绳或慢跑二十分钟。别小看这二十分钟它能让你的注意力和耐力明显变好。情绪上要学会接受失败和WA。备赛日常不可能每天都AC更多的是被题按在地上摩擦。关键是被摩擦之后能不能从每一道WA里学到一点东西。我把每一次WA当作一次“免费测试”通过错误反馈告诉我哪里还没想清楚。只要这个反馈被利用起来这次WA就是有价值的。最后再分享一个小技巧。我每次比赛前都会在纸上写一句话“保持专注先拿稳分再追难题。”这个简单的提示能帮我快速回到自己的节奏。备赛的核心从来不是“我今天刷了多少题”而是“我今天对算法的理解有没有更深一点”。把每天的时间花在真正能沉淀下来的积累上比赛结果自然会慢慢显现。