【比赛记录】2021年4月 ICPC昆明站

退役记

整个XCPC,从2017年10月买了第一本书《挑战程序设计竞赛》开始,一直学到参加2021年4月ICPC昆明站为止,历时3.5年的超长XCPC生涯终于结束了。整个大学生活除了XCPC真的几乎什么都不剩下了(可能唯一是2020年6月到9月摸鱼去腾讯参加了一段实习吧)。在退役的一场拿到了第一个也是最后一个金奖,还是金奖的倒数第一名,还是去掉打星队伍后的金奖的倒数第一名,能说什么呢,真的只是幸运吧。

从选赛站开始说吧,队友们都想去线下参加,我不太赞成线下因为我觉得到时候可能搞核酸隔离什么的就麻烦死了,事实证明线下推迟得太厉害直接等到现在疫苗都普及了。一开始考虑去不去澳门,虽然有港澳通行证但是怕境外真的要核酸隔离什么的,而且时间太赶了(没想到推迟到比昆明还后),就选了昆明。出了报名表之后看见很多强队,就有点慌了,仔细一个一个查强队们的历史战绩,肉眼可见比我们强一截以上的大概有接近50队,当时都已经无所谓了,战胜20个强队拿金牌什么的,我已经不指望了。

不过后面我们队伍每星期的三四六日都会开一场4小时的XCPC来练习配合,逐渐的大家很默契,在很多个赛区的录像里(在不小心看了赛后榜和听了赛后讨论关键字的情况下)拿了银牌金牌,觉得希望是逐渐提升的,但是具体提升是多少实在不清楚。联想起wls等使用CF分对区域赛成绩进行的估计,CF2000分对应金牌实力,仔细算了一下我们是2047分,也真的有金牌实力。回想起南京卡的那个树上背包,后来在div1的C见过,是个2400分难度的题,那么我感觉可以估计金牌题就是2400分难度,所以平均分是2047分的科技互不相同的三个人,在时间延长3小时并且配合默契的情况下搭配着打出2400分的题,是不是就是这个理论的来源呢?

最后证明这个理论可能是正确的,J题和M题都是要大家配合着通过的:J题M大佬和Q大佬一起从多个角度理解构造,然后一起检查代码是否实现有问题(没错我们真的有code review),还assert了一发确认代码实现没有错(意思就是算法错了),虽然后面数组开小了发生段错误(牛客网OJ居然会提示RE的种类?!)罚了20分钟,那时候可能心急了,还好全场只有那一次的小dirt,相比其他人的超过dirt次数我们最后真的就靠6分钟的罚时优势胜出;M题是q大佬推了很久的区间前缀和作差,然后指出是离散化后两棵对应区间的权值线段树的差值,然后在这个差值上面找不超过x的数的前缀和,然后他翻了翻板子发现他的主席树没有离散化的!我想了下好像比赛前一天晚上没睡着看了看2019年去徐州站的时候带的板子,里面有我亲手撸的全功能主席树!打开两年前的东西一看发现两年前的自己已经帮现在的自己离散化好了,建立主席树的整个流程也有详细的中文+代码的示意,还提供了全功能主席树的各种版本的实现指导!12分钟敲完整个主席树然后套上Q大佬推出的询问公式,再对一对样例,总共花了18分钟就过了这个卡了4个小时的M题!这就是传说中的“现在的你一定会感谢两年前努力的自己”吗?!作为一个两年没有见过杜教筛和主席树的人,新的模板里面都直接跳过了这俩了,没想到这一场退役站都出了,真的是不知道说什么了。

回过头说一下I题和K题吧:

I题是计算几何担当M大佬完全一个人单推的,另外两个人题目都没看,然后就1A了,学了几年的计算几何在关键时刻终于依靠快速实现和0dirt争取到罚时优势拿到金牌,M大佬应该很开心!

K题是个麻将题,最后看榜发现真的很多队伍都不会打麻将,就像我们队伍不会这个主席树一样。我们的实现就是枚举舍弃的牌和新加入的牌,然后dfs去check是否和牌,中间加入了一堆乱七八糟的剪枝并且这些剪枝一度把正确答案给剪掉了!我感觉这题确实是不好搞的,要有比较丰富的代码实现功底(卡常经验)和比较丰富的dfs经验。

第一件事就是搜索的时候状态的设计,这里是传统的用cnt[x][y]表示第x种花色的第y张牌的数量,放在全局数组里面进栈入栈时修改。然后搜索的应该是“每张牌去组合出什么牌型”而不是“由哪些牌型组合以及这个牌序由哪些牌组合”,这个假如第一步就错了应该就会写得很憋屈吧。然后就是要记录是否当前已经用过了雀头,否则就会搜索出AABBCCDDEEFFGG这种七对子,或者更离谱的AABBCCDDEEEFFF这种什么牌型都不是的组合。

然后就是要考虑怎么减少dfs的重复搜索问题,一种思路是对牌型状态进行hash,记录某种牌型是否是和牌牌型,这个我写了一下我就放弃了(好像清华是这样写的)。我改成枚举每一张牌参与的牌型是什么,也就是说假如这一张牌 ((x,y)) 参与组成 (a) 个雀头 (b) 个刻子 (c) 个顺子,一张牌组成顺子是指它作为顺子的最小的那张牌出现,那么需要满足下面的条件:

1、若 (a==1) ,则现在dfs的状态中,必须没有雀头,否则就有两个雀头了,是非法状态直接跳过。
2、 (2a+3b+c==cnt[x][y]) ,也就是恰好等于这张牌的所有出现次数,立刻在这一层就把这张牌的所有出现次数用完,这样以后就再也不会搜索等价的牌的状态了,这样避免了你搜索我我搜索你。
3、 (cnt[x][y+1] geq c, cnt[x][y+1] geq c) ,也就是这张牌真的能组成 (c) 个顺子,把后面的连续两张牌也用掉。

除此之外要注意,字牌是不能组成顺子的,还好打过日本麻将,不然看半天都不知道错哪。

第二种剪枝是:check成功之后要及时返回,因为这里只问是不是和牌,没有问和什么牌型,这里写成“在这一层及时返回”就比“在上一层不进入下一步搜索”要简单。

第三种剪枝是:可行性剪枝,每种花色的牌,也就是 (cnt[x]) ,都必须是 (3k) 或者 (3k+2) 的数量,并且为 (3k+2) 的花色必须只有恰好一种。这是一个超级大的剪枝,因为后面搜索立直之后听什么牌的情况,调用dfs前是随便枚举一张牌的话,大概率连花色内部的数量都凑不全。这个剪枝应该可以在暴力枚举“进张”的时候剪除掉90%的dfs搜索树,是真的直接从树根一刀剪掉了,是不是应该改叫“剪根”呢?

第四种剪枝是:重复枚举剪枝,这个是要在调用dfs前进行的,方法是给手上的牌排个序,然后枚举打出某一张牌的时候,若前一张牌和现在的牌一样,则说明已经枚举过了,直接跳过这张牌的枚举。

第五种可能的“优化”是:优先搜索字牌,因为字牌的牌型是固定的,只能有3k+2这种组合,假如是先搜索别的最后搜索字牌,这个步骤会重复在dfs的每个叶子出现,这样子调整搜索顺序会让搜索树的叶子消耗更多,但是枝干分叉更少,这个“优化”可能会是负优化。

这次比赛只用了前四种剪枝,从结果上看还好没写第五种,要不可能罚时就失去了那6分钟的优势了。

2021昆明 - 华南理工大学_单推圣人惠

写完M题的时候还有30分钟,手里还有一个不知道15怎么用的C题,实在已经假得放弃希望了。相当于挂机到结束看封榜了,看见最后是38名当时觉得挺失落的吧,因为感觉打星队伍不会有这么多在前面,M大佬执意要拿打星队伍名单数一数,发现前面打星的人刚好是3个,真的就正式队伍第35名最后一个金牌呗?不过我学了3年的数学,最后真的和自己预测的一样,几乎没有机会用上了,因为需要用数学的题可能已经是稳金之后了。2019年的徐州站和2020年CCPC的网络赛应该是我参加的正式赛里面唯一用到数学的吧。


流水账

H签到题,打好文件发现过了400个人,哇真滴nb,CF都不敢这么搞。没啥好说的,不过想diss一下那个10秒过题的。

L签到题,一开始q大佬就开了这个,我觉得还挺难的,后来觉得应该不要从图的角度考虑,直接贪度数,结果也是不对,突然意识到是不是每有一次下降就要开一种新的颜色(虽然也是错的)。后面还是直接归纳了,放a[i]的时候前面有j<i且a[j]>a[i]的,这些颜色都会和ai连边,所以每种颜色只需要保存最大值,这个就线段树或者树状数组维护一下后缀和就行。

I题,计算几何,m大佬偷偷1A的,都没来得及看。

然后开J题,并行排序,每次可以交换两个位置,问最少交换几次。一开始m大佬搞个每次每个环siz减半的,看起来很对,然后交上去挂了。

与此同时,一车人过了M,但是我们死活不知道M是干嘛的,还在想是不是不强制在线的话搞个莫队,或者弄个奇怪数据结构维护前面连续可取的一段和后面的一堆离散的点,但离散的点总是O(n)个,实在没想到怎么做。

搞不懂为什么全世界都会M,想着可能我们陷入坑里了。换题,我去搞K,打麻将。q大佬说这个麻将让我写,很快就行。hhh事实上我写了很久。

K很快可以dfscheck到自摸,用的各种奇丑的dfs,这时q大佬告诉我这套麻将可以有无穷张同样的牌,我这个就应该不对了,而且不知道怎么check立直,想了想直接暴力枚举换掉哪张然后调用上面的自摸就行了。

m大佬说想交一发assert看看是哪里错了,我其实是不太想的,可能我当时觉得J还是有机会的吧。

又过了一段时间,K的立直搞出来了,不过一直多了几种答案,打印出来看看。这时m大佬就交一发assert给J,WA了,这时说明J是算法问题不是实现问题,从结果来看这20分钟是完全值得的。

我想好之后,给K换了枚举刻子数量和顺子数量的方法,然后给搞了几个阴间剪枝,想着要不交上去试试吧。这时J题m大佬和q大佬也大呼“只需要操作两次”,反正没听懂,头一直晕晕的,他们交上去段错误了,居然!居然开小了!改了之后就过了。

我的阴间剪枝跑得飞快,K在J的2分钟之后就过了。

然后自闭的时间就开始了,期间去看了看C,觉得是个区间DP,想假了复杂度上去连T两发,是真的没睡醒。

然后往往复复不知道是看C还是看D,都不知道他们咋搞的,以为D是南京H的复现,上去演了一发,算咯。

在4小时封榜之后,准确说是15:07,q大佬突然意识到M这个东西可以用前缀和对应节点作差,然后求一段区间和加上去模拟。然后这个东西看起来就很主席树,这时候让q大佬去上机,我和m大佬看看有什么细节。不过q大佬的主席树没有离散化,就下来了,我突然想到昨晚我记得我两年前的板子里面有我的码农心血,找出来的时候是15:12,然后一路手速爆抄,再调了7分钟,在15:30的时候提交了一发1A。

然后其实当时就有点不太想继续做了,就开始装模作样的给C题反复交假算法,哈哈哈。挺有意思的吧,假如当时去看G可能30分钟可以?但是作为工具人的我已经很疲倦了,没有人能写了,我觉得还是放弃吧。

封榜出来38名,当时觉得有点可惜,m大佬非要去数数前面有多少个打星的,我觉得哪有这么多金牌打星队啊,算了吧。结果一看真的有刚好3个,我们就最后一个金牌的位置。

原文地址:https://www.cnblogs.com/purinliang/p/14615441.html