「杂录」THUWC 2020 游记

\(Day?\)

报名时间跨越了差不多一个星期多,这里打印一张那里上传一张,还挺麻烦的……最后申请还是通过了,看来\(CSP\)考得还不算太炸……

\(Day0\)

那么就坐飞机到北京去了。一起去的有同级的\(Tiw\)巨佬,高二的\(MasterYi\)\(Darkness\)大佬,还有两个初三的学弟,也是大佬。嗯,全都可以把我按到地上摩擦(更强的\(Freopen\)甚至因为早就已经拿到最高奖根本没去\(orz\)),果然我最菜了。

上午的飞机下午才到,由于有人要去\(PKU\),所以住的宾馆也不一样,\(PKU\)\(THU\)说是很近,但是走路的话还是要走好一阵子(本来想像上一次一样骑自行车,但是据说天气太冷,会冻手)。天气很冷,但是室内到处都是暖气,反而没什么感觉。于是和\(PKU\)的同学们分开,住进了离\(THU\)相对较近的宾馆。

试机在第二天,所以晚上并没有去\(THU\),也没有到街上逛,就在房间里复习多项式和生成函数的模板(然而最后发现并没有用上)。最后又打了一发半平面交的模板,洛谷上的模板交一发过了,没什么事可做,然后就休息了。

\(Day1\)

上午去报到,体感走了好久。\(THUWC2020\)的胸牌上还是\(2019\)年(大雾)。发了围巾,挺好的,就是最后都没开过封……

非正式选手莫得电脑,只能用自己的笔记本。既然用自己的,就没有试机的必要了吧……
于是试机(\(\times\)),模拟赛(\(\sqrt{}\))
第零题,\(A+B\ problem\),大概是拿来测试网站的,不知道为什么我的笔记本登上\(THU\)的网站很卡,总是要加载很久……
然后看看一眼第一题,排序+前缀和乱切,大概\(40min\)搞定了。
第二题,树上有多少个块颜色不超过\(2\)种,这很树形\(DP\)\(O(n^2)\)挺好求,但是空间时间都会\(GG\),先放着。
第三题,字符串,溜了溜了。

想第二题优化,没想出来。最后也没交(毕竟只是试机)。

题目挺好的,据说是\(THUWC2018\)原题。难度大概是递增,出来和\(Tiw\)大佬讨论了一下第二题,线段树合并维护一下值大概就行了,脑测了一下,细节较多。

中午回房间强制休息,咕掉了开幕式和合影(常规操作,我感觉我就没有哪次参加了合影)。

非正式选手比赛开始时间要晚\(35min\),不知道是为什么。\(THU\)里的机房提供的网络只能登上提交网站,于是只好趴在桌子上休息等比赛开始。

不知不觉\(35min\)过去了,比赛开始,看题。

第一题

题面:\(k\)个人,每个人有初始工资\(a_i\)\(n\)次操作,给定\(p\)\(b_1,b_2\cdots b_k\),如果\(b_p>a_p\),就把\(a\)换成\(b\)\(q\)次询问,每次给定初始工资(就是\(a\)),求最终工资。
数据范围:\(1\leq n,q\leq 10^5,1\leq k\leq 20\)

感觉挺简单的,容易发现初始工资第一次被换掉之后的变化方式就已经固定了,那么我们可以枚举第一次被换掉是哪个人的工资涨了。先单调栈把每次替换丢掉一个数组里面,再二分答案就可以知道这个人涨工资是在什么时候,对所有人取最小值即可找到第一次变化时间。那么输出以这个时间为起点的答案就好了。

处理以某个时间为起点的答案不难,可以在单调栈时顺便求出,复杂度\(O(k(n+q)\log n)\),理论上能过。从开始想到写完大概花了\(1h20min\),交上去\(Pretest\)过了,就没管了,去看\(T2\)

第二题

题面:一张有向图,\(q\)次询问,给定点\(x\)和步数\(s\),每次选择\(x\)的编号最小出边走,问走\(s\)次后停在哪里(若还有步数时无路可走也会停下)。第\(i\)条边走\(w_i\)次后删除,询问时走过的边的次数会留给之后的询问。
数据范围:\(n,q\leq 10^5, m\leq 1.5*10^5, s\leq 10^9 w\leq 10^{18}\)

这个题第一眼看过去就觉得恶心啊\(QAQ\)。考虑任意时刻,可走的边形成的东西肯定是基环森林(其中可以有普通的树)。由于出度最多为\(1\),那么每次询问其实就是先走到环上(路上如果走断了一条边得马上断开再接到另一个点上),然后在环上转圈,直到环断开或者走完步数。环断开的话也要再接上。怎么看都可以\(LCT\)优化,只是好恶心啊\(orz\)……

于是想着骗分,首先是\(O(\sum s)\)暴力跳边,若干小数据/随机数据都能跑过。然后\(w_i\)远大于\(s\)的,边不会断开,于是倍增就完事儿了。
这样加起来有\(41\)分。

还有树和基环树的情况,貌似很可做。
先考虑树,每次是从一个点开始向上爬一段距离,要求要么到达根要么到达一个断开的点(可以用爬升距离是否有\(0\)边判断)。然后给这一段的边全部\(-1\),似乎就没了。诶诶,链的话岂不是要树剖+线段树?然后找到第一个没有\(0\)边的位置,岂不是要二分?这样算出来……\(O(n\log^3 n)\)怎么搞……

刚了一会儿……最终决定还是打了这个算法,结果\(O(n\log^3 n)\)果然爆炸了……

于是滚去看第三题了……

第三题

题面:一棵单位边权树,给定常数\(X\)\(m\)次询问,问\([l,r]\)的点构成多少个联通块,两个点相连定义为距离不超过\(X\)
数据范围:\(n\leq 3*10^5,m\leq 6*10^5\)

神仙,不会,自闭……

慢慢翻看部分分有什么可以拿的,\(4\)分暴力,\(4\)分输出\(1\),其他\(GG\)

出考场

\(Day1\)大概是\(100+41+8=149\),我好弱啊……和\(Tiw\)大佬讨论了一下,貌似就少了第二题的树,其他的大概是大众分。

晚上敲了一个网络流模板就休息了。

\(Day2\)

早上起来徒步走到清华,走了大概\(15\)分钟吧,可能有一公里远?
上午的比赛不知为何额外延迟了\(20min\),比赛完后都要\(2\)点了。

第一题

题面:\(n\)份报告\((ai,bi,ci)\),初始兴奋值\(s\),听一次报告兴奋值变成\(a_i*|s|+b_i*s+c_i\),重新排序报告,求最大兴奋值。
数据范围:所有输入值绝对值\(\leq 15\)(含\(n\)),答案可以用__int128存。

这个怎么看都是状压\(DP\)啊……似乎是\(3^n\)?但\(15\)\(3^n\)很卡的吧。而且看不出来有什么需要\(3^n\)的地方……
再考虑了一会儿,发现每个兴奋值都是个分段一次函数,具有典型的单调性。所以,最大的结果肯定是:最大正数、最小正数、最大负数、最小负数其中之一代进去的答案。然而问题可能有点大,我们要计算的不仅仅是最大结果,因为中途要用到正、负分别的最大值和最小值,而最小值由于规定了符号,相当于越接近\(0\)越好,无法单调。

这个时候猛然想到,\(c_i\)的值也很小,并且若\(c_i=0\),就是两个正比例函数,只要代入的数符号不变,符号就不会变。
所以若兴奋值的绝对值达到一定大小后,让\(c_i\)再也无法让这个数变号,那么就不存在求最小值时可能出现的问题了。那么当绝对值小的时候暴力计算合不合法,绝对值大的时候记录正负分别的最大值、最小值即可。由于\(n,c\)都很小,只要当值在\([-225,225]\)的时候暴力存就好了(更大的就算每次斜率为\(1\),截距\(15\)都没有办法变号)。复杂度\(O(450*n*2^n)\),而且不严格,时限也宽松,能过。

大概花了\(1h20min\)码完了,一次过,去做第二题了。

第二题

题面:一个\(DAG\),源点为\(1\),按题目要求得到一个\(DAG\)的生成树,根为\(1\)\(q\)次询问\((a,b)\),保证树上\(a\)\(b\)的祖先,问删除树上\(a\)\(b\)简单路径的边后,\(DAG\)上从\(1\)出发\(b\)的子树中有多少点不能到达,询问独立。

\(n,m,q\leq 10^5\)

考虑到,\(DAG\)去掉一棵类\(Dfs\)的生成树还剩什么,交错边和前向边。
然后就分别看,前向边,在删除祖先的链时可能没用,要看具体删到哪里了;至于交错边,他们的起点不是终点的祖先,所以删掉祖先链没影响,好像任何时刻都能走到(此处\(Flag\)之后发现是错的)?那么考虑询问是什么样子的。

最后能走到的点,显然是若干个子树,每个子树的根能用前向边和交错边走到被删除位置的上方(也即,\(a\)点的上方)。那我们应该尽可能使用他们跳到深度最低的位置。那么有交错边直接可以到根(此处还是\(Flag\)之后发现是错的),有前向边就和前向边指的点能到达的深度最低的位置取更浅的即可。

然后求答案怎么求?可以对每一个子树维护一个线段树,\(i\)号点的线段树,下标为\(j\)的点存的值是:删除\((fa[i][j],i)\)的时候的答案,其中\(fa[i][j]\)表示\(i\)往上走\(j\)条边的祖先。

那么我们把询问离线放到每个点上,只需要求出每个点为根的子树的上述的线段树即可。考虑如何求?首先,若\(i\)无法到达(被删除的边达到了\(i\)用前向边和交错边能到的最浅祖先),答案应该是儿子的和,直接线段树合并!然后\(i\)能够到达的最浅祖先若没有被删除,整个\(i\)的子树都可以到达了,那么这部分可以直接全体赋值为\(0\)

看起来蛮简单的,噼里啪啦就开始打了。测样例,全过,提交,刷新,\(WA\)\(0pts\)

当时我就傻了\(QAQ\),写个暴力准备对拍。写完才突然发现我要造一个\(DAG\)\(1\)号点还要能到所有点?询问还要保证是祖先?于是痛苦地打了一个勉强符合数据范围的弱生成器,\(n\)\(10\)以内还真拍出来了。然后终于发现交错边并非一定能走,把\(LCA\)给删掉了就不行了。仔细思索,发现交错边\((u,v)\)中的\(u\rightarrow LCA(u,v)\)这一条链可以随便走,那么其实和前向边完全可以统一起来。往上走的最浅祖先应该与这条链上的点们取更优。于是拓扑排序把最浅点求出来,倍增维护\(LCA\)和最小值,再重新套上线段树合并,要改的内容并不多。

于是最后打了\(200\)行,测数据全过后提交,\(AC\)了,舒服。

结果这么一折腾,没什么时间看第三题了……\(GG\)

第三题

题面:一颗点权树,点权组成\(1\cdots n\)的排列,\(m\)次询问,给出一条路径,将路径点上的权值组成一个序列,问有多少序列满足冒泡排序k轮后等于这个序列,\(\%998244353\)
数据范围:\(n,m,k≤5*10^5\)

没时间了加上题目太神仙,拿了\(5pts\)暴力就走了。

出考场

\(Day2\)\(100+100+5=205\),交流了一下好像算是大众分,回去休息了。

\(Day2+\)

工程题,\(Cache\),看学习手册看了\(30min\),还是基本一头雾水,大概就看懂了两个实现的部分,一个是\(Cache\)的替换算法,另一个是多个\(Cache\)\(MESI\)算法。

第一题就是\(MESI\)的大模拟,看起来挺简单,准备做。
由于学习手册并没有告诉我读和写操作是读和写在哪里,我纠结了很久是改\(Cache\)还是改主存,最终大概知道了是改\(Cache\)
以为自己基本理解了是在干什么,开始打了,大概就是跟着手册的操作做,但是它讲得很迷,并且对于第一题,有些步骤没有用。写完+调试花了接近\(1.5h\),发现很多错误。首先是手册里面有些表述没有用英文函数表示,导致没看到。同时表述里面有\(Flush\)也有\(Flushopt\),且\(Flushopt\)在题目里面没有传递数值,却依然要输出这个操作。而\(Flush\)则是题目加入的学习手册里面没有的操作。于是我把两个操作当成了同一个……样例却太水,没有显示出这些细节。自己都不知道是啥的东西,也造不出小数据。

最后\(WA\)\(5\)发终于调对了,拿到\(40\)分。看第二题发现是大水题,\(Cache\)的替换操作多种同时实现。一个一个写,毕竟多一个就多\(8\)分,最后一个\(16\)分。

然而写完还剩\(15min\),发现输入出了问题。原来输入的是\(16\)进制数,我用快读输入不进来。于是改成读一个字符串,结果脑抽了写成二进制,样例水还能过,但是交上去就\(WA\)。最后发现的时候只有\(3min\)了,要判断字母和数字两种情况,没写完……\(GG\)

出考场

发现就自己一个人只做了一道题,后面的题目都不难,而且很好理解……

\(Day3\)

非正式选手没有接到面试通知,在宾馆玩了一个上午,然后就坐飞机回去了。
其他同学都拿到了挺好的约,不过据说这次发约都是满天飞,有点担心约不值钱了。

这次表现还算勉强吧……前两天还算大众,最爆炸的是\(Day2+\)没有安排好时间,并且没有读懂材料就开始打代码,导致后面的简单题失分。

posted @ 2019-12-25 18:32  ModestStarlight  阅读(745)  评论(0编辑  收藏  举报