写在前面ACM-ICPC校赛对很多人来说可能只是简历上的一行字或者是某次机房里的热闹但对真正参与过的人来说它更像是一场心照不宣的硬仗——尤其是当这场硬仗还带上了“同步赛”三个字。我不是西安邮电大学的学生这次是跟着学校队伍去打的“西安邮电大学第五届ACM-ICPC校赛同步赛”。所谓同步赛就是和现场赛同一时间、同一套题但彼此外部参赛、各自独立机房。我们把这场同步赛当成一次难得的练兵机会总体打下来有几个题目直接把我写到怀疑人生但也有几道我们队伍靠配合硬啃下来的。这里把整场从备赛到复盘的全过程记录一下希望给同样在ACM边缘挣扎、或者正在备战下一场校赛的朋友一点参考。1. 赛前准备三天时间我们做了什么1.1 同步赛和现场赛的定位差异决定了策略完全不同先说结论同步赛不是去“赢”的是去“验货”的。验什么验队伍水平的成色验自己在高强度限时压力下的真实反应验那些刷题时以为会了、上了战场才发现根本不会写的知识点。现场赛的选手在机房里有滚榜、有现场氛围、有AC时队友之间的眼神交流这些东西看起来不重要实际上非常影响心态。而同步赛在外面打心态往往是“打不过就跑”这种放松感会在某些时候帮倒忙——比如该认真推导的题目草草写个暴力就交了最后罚时白白拉满。所以我们这次备赛的核心思路就一条把三天时间当成两天用来补齐薄弱板块剩下一天纯模拟。不是那种“打开OJ随便刷几道”的模拟而是严格按赛程时间上午十点到下午三点全程五小时不允许暂停、不允许查题解就两个人一台电脑我们队只去了两个人第三个人临时有事。1.2 阵容与分工两个人怎么打一场五小时的比赛ACM-ICPC正式队伍三个人我们这次同步赛只有两个人但这反而逼出了一个非常有效的分工模式。我主攻思路和代码实现另一位队友H主要负责读题、找规律、构造样例以及在我写代码卡住的时候做“人肉调试”——就是他用笔在纸上模拟我代码的执行过程帮我定位逻辑错在哪。这招在打同步赛时极其好用因为现场最贵的就是“来回改代码的时间”一个人写代码犯迷糊另一个围观的反而能一眼看出问题。具体分工表大概是这样时间窗口我在做什么H在做什么开赛前10分钟把模板代码框架用编辑器提前写好包括快读、常用头文件、并查集模板浏览全卷题目判断每个题的难度和知识点给题目建立初步顺序表前30分钟迅速切掉签到题继续补完剩余题目的题意理解分析样例中期1-2小时攻克算法题优先做有把握的构造边界样例实时验证我的思路是否漏洞最后2小时写复杂题、修bug复盘罚时情况合理放弃这个表看起来简单实战中真的有效。尤其是“浏览全卷”这个动作很多队伍开赛后第一件事就是冲签到题结果签到题卡住半个小时回头发现后面的题其实更简单。H这个习惯帮我们避免了至少两次这样的翻车。1.3 工具与环境不光是带个U盘那么简单打同步赛另一个容易被忽略的点是环境一致性。现场赛的机房机器、编译器版本、桌面环境都是固定的但我们同步赛在自己学校机房打操作系统、编译器、IDE都和主办方可能有差异。我们这次提前做了三次“同环境测试”把编译命令、标准输入输出方式、文件读写的模板全部统一成和比赛平台一致的模式。特别注意了C的版本问题如果比赛评测机是C17而你本地默认C11某些语法特性比如结构化绑定可能在本地能过、提交就编译错误。我一个朋友之前打区域赛就吃过这个亏所以这次我们老老实实把编译标准改成了C17。还有一个小细节输出数据的行尾空格和换行符。本地看不到判题机会因为多一个空格直接WAWrong Answer。这些细节不是知识性问题纯粹是经验问题但就是这种经验问题能让你在比赛中莫名其妙地少罚时。2. 赛题复盘六道题四种命运2.1 整体难度分布不是每道题都值得死磕这套题一共六道按我们的视角编号为A到F整体难度呈现明显的阶梯结构。A题和B题属于签到题C题和D题是套路题E题开始上强度F题则是标准的“防AK题”。这里说的防AK不是知识点多难而是多知识点叠加、思维路径极长的那种题。很多队伍的一个常见误判是把所有时间平均分配。正确做法应该是赛前就定好“放弃线”——到某个时间点还没思路的题果断跳过。我们这次设定的线是比赛剩90分钟时如果F题还没有完整思路直接放弃把时间全部砸给E题和D题的优化。事实证明这个决策让我们保住了不少分。F题最终我们连提交都没提交但E题靠最后45分钟写出了一个高分偏解拿了80%左右的测试点分这在ACM赛制里已经是很划算的交易了。2.2 A题复盘签到题为什么是三道而不是一道A题是一道纯签到题大意是给定若干操作模拟一个计数器在范围限制下的加减过程。看起来毫无技术含量但我见过太多队伍在签到题上翻车。我们AC这题用了7分钟不算最快但在正常范围内。复盘时我发现一个关键点A题的设计看似简单实际上检验的是选手对“多组输入”处理方式的熟练程度。这里的输入不是简单的T组循环而是“输入直到文件结束”的模式。如果你习惯了每道题都先读T再循环这题容易在读入方式上踩坑。我个人的习惯是所有输入IO全部用快读模板统一处理不管题目是T组还是EOF结束代码框架都能无缝切换。很多新手忽略了这个细节写while(T--)写习惯了遇到EOF直接超时或者死循环。2.3 B题复盘麻烦的“简单题”B题是个离散化前缀和的问题题目背景换了个包装说是统计某个区间内的元素种类数。知识点本身不难但在赛场上很容易被“离散化”这一步绕晕。老手都知道离散化的核心不是排序去重那么简单而是要把坐标压缩后的映射关系理清。我当时写题的时候用了map存映射代码倒是短了但在数据量大的时候map的常数开销很要命。后来复盘时查阅了题解发现标准做法是sortuniquelower_bound复杂度直接从O(n log n)的常数巨大变成O(n log n)的小常数。这种题型的教训是越基础的题越要选稳定的实现方式而不是看起来聪明的写法。赛场上的时间是按分钟算罚时的map在1e6的数据量下能慢整整一秒而这1秒在极限数据下可能就是TLE和AC的分界线。2.4 C题复盘一道我们AC但心里直冒冷汗的题C题是一道背包类问题但不同的地方在于它的物品数量很大、体积种类很少。这种“多数量少种类”的背包模型最经典的优化思路是利用二进制拆分把多重背包转成01背包。我们队的解决过程比较曲折H读完题之后第一反应是“这题直接贪心”我立刻否决了因为背包问题里贪心几乎必挂。接着我尝试了二进制拆分但写完后发现一个细节——物品价值并不是单调的导致局部替换策略失效。最后我们换了个思路用分组背包的思路把同体积的物品组内排序然后优先取价值最高的组合。这种题的复盘价值在于不是所有背包都要写成板子有些题需要你现场改板子。我们最初直接套的模板跑出来超内存内存超了的那种感觉真的是哑巴吃黄连——明明思路对但因为板子不适合白白浪费了半小时。2.5 D题复盘最可惜的一题也是最涨经验的一题D题是一道图论题题意是给定一棵树要求动态维护某个点到所有叶子节点的路径权值之和。看到“树”和“动态维护”两个词同时出现我的第一反应就是树链剖分。但问题在于我们虽然带了树链剖分的板子但那个板子是我前一天晚上临时从代码库里翻出来的自己从来没有现场默写过。于是发生了经典的“看板五分钟写板五十分钟”——核心思想和线段树部分我都懂但一到剖分序和线段树的位置对应关系就绕晕了建树测试的时候反复出现段错误。最终D题没能在比赛时间内AC提交了一份超时的偏解拿了部分分。赛后我重新把树链剖分的板子从头到尾手写了三遍写到第三遍时已经不需要看任何参考了。这就是赛场的残酷之处你脑子里“知道”和“能写出来”之间隔着一道巨大的鸿沟只有反复默写才能填平。如果让我给还在备赛的朋友一个建议那就是板子一定要自己默写不要依赖代码库复制粘贴。你以为复制粘贴能省时间实际上维护板子与题目的接口适配会花掉你更多时间。2.6 E题复盘45分钟的偏解是如何炼成的重点说说E题。E题原题是个期望类概率题数据范围给得很宽正解应该是动态规划加矩阵快速幂优化。但我们在比赛剩90分钟时才刚开始看E题显然没有时间写正解。我当时的判断是这道题的部分分梯度非常明显最低档的测试点只有五个完全可以暴搜。中间档的测试点规模虽然不能用纯暴搜但可以用一个“不保证完全正确”但期望正确率很高的近似算法去碰运气。于是我用了一个很朴素的蒙特卡洛思路随机模拟大量路径统计期望值的近似结果。这个思路在概率题里是通用“混分利器”——但它有个致命缺陷如果路径数量呈指数增长随机采样极易漏掉高权值区域。为了降低漏采风险我给采样加了一个贪心偏置从当前状态出发时优先选择局部期望值最高的转移方向其余方向按概率随机探索。用这个偏置采样去跑果然测试集里大多数小数据都过了甚至有几个中等数据也拿到了不错的分。最终E题拿了大概80%测试点的分数对我们来说已经是超额完成了。这里分享一句心得ACM里没有“混分”的说法拿到的每一分都是竞争力。别觉得偏解丢人很多AC代码的初始版本就是偏解只是后来被测试数据逼着补成了正解。你在赛场上能做的就是在数据不允许试错的情况下评估偏解的风险收益然后大胆执行。2.7 F题复盘放弃也是一种策略F题是个综合题需要用到后缀自动机加线段树合并光是这两个知识点就够我们喝一壶了更何况还要结合动态规划的思维去推导状态转移方程。我们在赛程进行到210分钟时看了一眼F题H花了三分钟读完题意然后转头对我说“这题咱们别碰了。”我一开始还有点不甘心毕竟F题分值最高。但冷静想一下从当前时间去碰F题最优情况下可能写出一个能过前两个测试点的暴力这个期望收益约等于10分但如果把同样时间用在检查前面几道题有没有低级错误上挽回的罚时和AC收益可能远不止10分。于是我们选了后者。事实证明这个选择是对的。我们在最后半小时的检查里发现C题有一个数组越界的边界隐患修掉之后减少了三次提交的罚时每次罚时20分钟三次数就是60分钟这个“赚到”的时间比硬写F题划算多了。3. 比赛过程中的真实体验时间、节奏和心态3.1 前30分钟抢开局的艺术比赛开始前的十分钟我们做了一件事把电脑桌面上所有弹出的静默更新、杀毒软件弹窗全部关掉。别小看这个动作比赛过程中任何弹窗都可能导致你思路断片等你回过神来看题目已经不知道自己在想什么了。开赛后前20分钟我直接切A题然后快速AC。H那边同步快速浏览B到F题的题目把每道题的“初步标签”写在本子上比如B题是“离散化区间”、C题是“背包变体”、D题是“树链剖分”。这些标签并不保证正确但能让我在切换题目时有初步方向。前30分钟做对的三件事快、准、稳。快指的是不纠结任何细节签到题就是签到题不要去想什么最优实现用你最有把握的写法AC就行准指的是对题意判断要准这是一道模拟题还是一道思维题直接决定你接下来投入的时间量级稳指的是不在这30分钟内盲目开题宁可晚点AC也不要提交WA增加罚时。3.2 中期2小时从“做出来”到“做好看”比赛进行到1小时左右我们已经AC了两题第三题C题还在调试。这时候心态上最大的挑战是看到周围队伍虽然是外部同步赛的其他队伍不停有AC的提示弹出而自己的代码还在编译错误这种对比会带来极强的焦虑感。应对焦虑的办法只有一个——给自己设定一个微观目标。比如当时C题我们反复在边界条件上出错我就告诉自己下一步不是“AC”而是“把边界样例全跑对”。一旦目标缩小焦虑就没了专注度反而提高了。中期也是犯错的高峰期。我们在这阶段犯过一个典型错误B题离散化时index从1开始还是从0开始没想清楚导致前缀和的查询区间全错。这种错误的特点是你单独看每一行代码都没问题整体跑起来就是不对。排查办法是盯着样例的数据流一点一点过别靠眼睛看代码靠纸笔算。3.3 最后90分钟保分还是冲难题比赛进入最后90分钟时我们大概的分数是AC了三题D题部分分E题未开。此时面临的决策是冲E题还是回去打磨D题。我们最终决定冲E题原因很简单D题的偏解已经拿到了部分分而E题的期望收益更高。这种“放弃同一个模块里的优化、转攻另一个模块”的判断在ACM赛制里其实非常常见。关键就是你要能估算出两个选择的期望得分以及对应的概率。具体算一下D题已经部分AC按照测试点梯度大概是55%的分数再优化能提到70%左右概率约50%期望收益是7.5分E题如果从零开始写偏解预估能拿30-80%不等概率约40%期望收益按中间值算也有20分左右。收益差两倍多闭着眼睛都知道选哪个。3.4 同步赛的“隐形压力”没有掌声的战场最后聊一点同步赛独有的话题环境差异对心理的影响。现场赛有滚榜有工作人员走来走去有隔壁队伍的键盘声——这些干扰看似负面实际上会持续给你提供“我们在比赛”的紧张信号让你随时保持亢奋。而同步赛在自己熟悉的地方身边是熟悉的机房没有实时排名滚动很容易进入一种“这是我的日常刷题时间”的错觉。这种错觉非常危险。我在比赛进行到2小时左右就明显感觉状态下滑手指敲键盘的节奏慢了甚至中间停了几分钟发呆。后来强行给自己制造紧张感我把手机调成倒计时放在屏幕边上每隔十分钟响一次每次响铃都提醒自己“时间正在流逝”。这个小技巧在后面三个小时里起到了极大的提神作用。4. 赛后复盘哪些习惯值得留下哪些坑下次要绕开4.1 板子问题临时抱佛脚佛会踹你一脚这次比赛最让我印象深刻的问题就是D题的树链剖分板子。我赛前只是把代码库里的板子过了一遍眼睛没有实际敲过结果真正用到的时候就暴露了。赛后我把这次比赛涉及的全部数据结构类和算法类知识点列了一张清单逐个标注了“能够默写”“需要看参考”“完全不会”三档。结果很扎心能够默写的不到一半。接下来的一周我每天抽一小时用纯手写的方式过一遍“需要看参考”的板子直到把它们全部变成“能够默写”。我的建议是备赛阶段把算法按“高频、中频、低频”分类高频算法并查集、最短路、最小生成树、线段树、树链剖分、DP常见模型、GCD/exgcd全部练到默写级中频算法后缀数组、AC自动机、网络流、动态规划进阶练到看到题能快速定位并写出框架低频算法计算几何、FFT、数论进阶视时间和精力随机应变。4.2 队伍配合两个人也可以是一支队伍很多参加同步赛的队伍可能和我一样出现人员不齐的情况。这时候不要觉得“反正人少就一定弱”。两个人配合得当效率完全可以超过三个人的松散队伍。我们的配合原则就两句话写代码的人靠谱读题的人就要敢“否定”。H经常在我准备开写某道题的时候说“这不就是XX模型吗你用XX方法”虽然有时候他对有时候他错但这种互相碰撞的讨论比一个人闷头想效率高多了。场上永远有一个人在看时间。不是简单看还有多少小时而是看“当前这道题已经投入的时间”每道题设定一个内部预算超了就强制切换避免陷入“我就快调出来了”的错觉。4.3 数据范围与测试别只在样例上跑通了就交复盘时我统计了一下这次我们一共提交了11次其中WA错误答案占5次RE运行时错误占2次TLE超时占1次AC占3次。这个数据很不好看说明我们的测试意识还有很大提升空间。WA多说明边界考虑不周RE多说明数组开小了或者指针越界TLE说明算法复杂度估算不准确。改进方向是每次提交前至少自己构造三组样例——最小边界比如n1、最大边界比如n1e6、特殊极值比如全是重复数据。不要觉得浪费时间一次WA的罚时20分钟足够你构造十组样例了。4.4 复盘清单每次比赛结束后的固定动作我们这次赛后复盘形成了一个固定流程分享出来供参考先把所有AC的题代码重新读一遍找出可以优化的地方不是为了重写是为了养成自己的代码习惯。把每个未AC的题写出题解分析至少清楚正解思路并且自己手动推导一遍状态转移和边界情况。整理一份“失误清单”记录这一次比赛的每一个低级错误比如数组越界、类型开小、忘记初始化下一次比赛开场前看一遍。最后把罚时数据做个统计算出平均每AC一题需要花费的提交次数这个数值反映了队伍的调试能力是否健康。5. 关于参赛本身的一点体会打这场西安邮电大学第五届ACM-ICPC校赛同步赛之前我的预期是“能AC三题就不错了”最后的结果其实是AC三题加两个部分分超出了预期。但比结果更值得记录的是比赛过程本身逼出来的认知升级。我最大的感受是ACM比赛的魅力不在于你知道多少算法而在于你如何在五小时内合理分配你的“知道”。你不可能五小时内什么都做到最好但你可以决定哪些题值得写偏解、哪些题直接放弃、什么时候检查代码比写新题更划算。这些决策习惯不只是打比赛有用做任何技术项目都是通用的。如果你也准备参加类似的高校校赛不管是现场赛还是同步赛我的经验是不管队友到没到齐先把流程走完——提前一天准备环境、赛前十分钟规划分工、比赛过程中记录每道题的投入时间、赛后认真复盘犯过的每个错误。这套流程跑一次你的收获会远大于那几道题本身的分数。希望这篇复盘能帮到你哪怕只对你的一次决策产生了影响也不枉我码这么多字了。下一场我们赛场见。