赵晟昊IOI 2026参赛总结IOI 2026参赛总结2026-08-28 11:45:20

 
 

非常荣幸能作为中国队的一员参加在乌兹别克斯坦塔什干举办的第38届国际信息学奥林匹克竞赛(IOI 2026)。

赛前国家队先后在四位队员的学校举办了集训,各段集训一般都安排模拟赛,还针对IOI风格的题目做了不少训练,尤其是交互题、构造题、提交答案题这类我们平时接触比较少的题型。87日晚上我们先到了北京,第二天白天开了个简短的动员会,下午出发去机场,当地时间晚上10点抵达塔什干,一出机场就感受到了主办方明显的热情。第一晚我们住在Qashqadaryo Hotel(卡什卡达里亚酒店),两人一间,之后就换到了Xorazm酒店,三人一间,一直住到赛程结束,两家条件其实差不多。塔什干比北京晚3个小时,时差不大,这点比较幸运。饮食以肉食为主,碳水只在部分时间出现,大多是炒饭和烤包子,不过我吃得还挺习惯。

比赛前我已经认识了不少国家的选手。华裔选手大多会说中文,交流起来没什么障碍;甚至有挺多人会打三国杀。正式比赛前有一场练习赛,题目用的是和去年一样的四道题。有趣的是,第二题我们四个人里只有一个人会做。

DAY1811日)的三道题是Tiling GameMonumentsBall Machine。比赛一开始我先花了10分钟配了下环境,然后开始看题。Tiling Game是一道交互题,我决定先做它。我注意到关键是让白格始终朝向外角,棋盘上就不会出现四格全黑的2×2;实现是找从外圈到内圈的第一个空位,蛇形放置。没想到一次就通过了,在0:30:58拿到了100分,开局顺利让我心里踏实了不少。

Tiling Game一次通过后我看了看剩下的题,Monuments看上去很简单,是一定要过的题,就接着做了。我先想的是让正负平衡:把碑按位置分成左边、中间、右边三堆,左右数量对不齐的时候先动中间的补,中间的用完就从多的那边拿,让两边数量一致。然后将剩下的碑按|x|从小到大排成一列,一层层处理,做一个O(N²)dp,状态记两边各还差几个。每层先把上一段距离的代价摊进去,距离差乘上两侧剩余差的绝对值之和,再按这层碑朝向哪边扫一遍前缀最小值。写代码的时候发现不对,改了一下就对了:固定碑里位置互为相反数的直接配对消掉,多出来的碑放到中间才对。第一次交上去只有3分,那时已经1:29:58了;改完是49分,在1:38:10达到。后来我打了个表,注意到这个dp的差分数组是凸的,可以直接用平衡树优化,于是换成了无旋Treap,每个操作O(logN),在2:12:20拿到了100分。这题比想象中顺利。

接着做Ball Machine。这题的代价Ccollect次数加上最大球值,满分要求C≤44。我想了一些做法,心里没底,就先写了个暴力交了:对着第i片叶子反复插同一个值M−i−1collect一次,球的值就是搜索顺序的线索,按它模拟DFS的过程,可以把整棵树的父子关系还原出来。这个做法的代价等于M,在2:38:40交上去拿到47分。之后才开始真正做,用的分块编码:先把前2B个叶子的信息一次收集出来,重建出树的骨架;之后每次只处理B个叶子,把已知部分上的旧球按一组固定标签重新插回去,插完新一批叶子再收集一次,用收集结果把新出现的子树逐步挂到骨架上。这样collect次数约为M/B,最大球值约为2B,代价C≈M/B+2B。把B定为15时代价刚好是43,可以满分。我写完以后,把小样例和本地随机数据都调过了,但提交后只有十几分,一时找不出问题。经过一番调试,后来发现收集结果里相同值的球顺序是不确定的,只看最后的位置会出错,改成向前扫描最后一个满足条件的位置才修好,最后在4:47:46获得了100分。在剩下的时间想了一下,发现其实可以做到C=39,比满分的限制优秀了很多。这题花的时间比我预期长了不少,不过结局还是好的。DAY1结束了,我三题都是满分,出来看榜这一天是单日第1。当晚还是挺高兴的,不过还是按正常节奏休息。

DAY1结束的晚上,我们和新西兰、美国、澳大利亚的队员一起打了三国杀。812日是休息日,主办方带我们去了城郊的Magic Safari(神奇野生动物园),它是中亚第一座主题野生动物园,狮子、袋鼠这些动物散养在仿自然的环境里。

DAY2813日)的题目是Classroom GameMagic CityPartition。我先做Classroom Game,通信题。这题我直接尝试拿100分,写了第一个做法:每条纸条放学生的位置i和它各自的计数值f[i]f[i]记的是这个位置最近一次举手的轮次。关键是用了"纸条被改写"这个事实:某学生的纸条在他举手的那一轮不会被改写,f值会从前一轮的信息里继承下来。为了区分"没举过手""最后一轮举了手",我还用了(-1,m)互换编码,每条纸条长度2,代价C=2。第一次交上去只有4分(0:26:48),改了几轮后拿到前三个子任务的19分,那时已经0:42:37了。我很快发现了过不了的原因:纸条被打乱之后,之前举手的人留下的信息会错误地流传下去,后面就没法判断了。又想了一会儿,感觉这个问题一时难以解决,为了不耽误后面,我先把这题放一边,去做别的题了。

看到Magic City是提交答案题,感觉这个题很难,就先做Partition了。我最初的想法是贪心:第一个人把所有数从小到大排序,划分为若干段,试图让每组和尽量接近均值,往每个段塞一个数,这样每个段都是一个连续段外加一个数,第二个人就可以从大到小,每次能取就取,不能取就试着再找一个数。写完发现第一个人可能根本找不到合法的划分。接下来改成二分"每组和的上限",用前缀和贪心数一数能分成几组,再按这个上限切分,又加了个向均值靠拢的调整,但还是不对。交上去分数也一直没上去,先只有7分,之后也只到11分(2:42:58),那时已经2小时43分了。再后来,我想的是"最小允许和L"这个角度:每组的和应该都在[L,L+V]里,用一个DP判断可行性。f[i]存的是前i个数最后一段的和落在区间内时,能分出的组数范围[最少,最多],转移要枚举段和范围满足条件的前驱,用二分找这个前驱区间。先二分出最小的可行L,再固定L做一次DP回推构造。这个方向我觉得没问题,第一个人确实能找到一组合法的方案,但是最后发现第二个人又有问题,怎么修都过不了对拍。于是我发现,我在这个题上的所有做法全都是错的。此时时间已经只剩一个多小时,我的总分才30分(Classroom19分加上Partition11分),我感受到了巨大的压力。

我去上了个厕所冷静了一下,放下Partition去做Magic City。我给每种类型各建一个点(一共2K个),按编号模4分成四组,组间连完全二分图、组内自连,再补几种环形连边的方式,保证任意三组之间都能找到路径,这样每一个三元组都能落到某个组的组合里。交上去先是25.24分(3:42:00),又优化了一下,在3:55:23到了43.16分。麻烦在于K为奇数的时候。每组大小不一致,同样的连边方式下有的点会超度数,我加了两个"额外点"塞进各组,改了几轮,发现我的偶数做法很难塞进额外点。于是干脆把奇数和偶数分开修成两份代码,但两份不能兼容,给一份修就会把另一份弄崩;中途还有一次我把连边列表抄错了,一组重复一组漏掉,那次提交的分数直接崩了,幸好后来又修了回来。最后只能两份代码各拿各的分,按子任务分别取最高,在4:24:53凑出67.78分。这种构造题还是练得太少,赛场上的编码密度又高,想把奇偶统一处理时总有些边界想不明白。

29分钟的时候我回到Classroom Game,发现加一个数就能得到一个简单的做法:额外记录每张纸条写入时的轮次R,校长只看"最后一轮仍未被改写的纸条",直接取里面的信息。代价从2变成3,按规则得分要乘0.75,剩下子任务的81分折成60.75,但正确性有保证,我觉得这笔交易是划算的。把代码写出来交上去,在4:30:4579.75分(19分加上81分打七五折)定了下来。最后十分钟我回到Partition写指数暴力:第一个人把排序后第i个数进第imodm组,再给不够的组补差数;第二个人用子集DP。写完发现过不了N≤10的子任务,于是加了一个优化:如果总和等于平均值的子集特别少,就直接枚举这样的子集,就通过了。最后的十来分钟里我连着交了6份,在4:42:59把分数从16分补起,最后一份提交在4:49:57,到了26分,离交卷只剩十分钟了。然后比赛就结束了。我感到我的DAY2成绩很差,事实也确实如此,单天排名第32名,最后由于DAY1的优势苟住了金牌。

最后结算两天的分数是(100+100+100)+(79.75+67.78+26)=473.53分,全球第3,金牌。中国队拿了31银,团体第一,许淇文以498.27分得了全球第一,恭喜他。

现在回头看,问题主要在第二天的取舍上。Partition我在正解上耗了太久,写了一套自以为正确的方法,结果第一个人可行、第二个人不行,对拍怎么修都过不了,要是能早点判断出这个方向一时半会儿做不完,先把拿得稳的子任务拿到手,总分应该会更好。Magic CityK为奇数的情况上花的功夫也多,说到底还是平时构造题练得少。

最后感谢CCF给了我们参加IOI的机会,感谢赵启阳老师、蒋婷婷老师和各位随队老师:赛前为我们翻译题面,旅途中安排住宿与出行,比赛期间也一直跟进竞赛进程;感谢我的教练毛丹怡老师,从2023年入校起一直带着我;感谢队友许淇文、刘家炜、何宇翔;也感谢金华一中的老师和同学们,以及一路支持我的家人。下一届IOI在德国举办,祝中国队再创佳绩。