Codeforces Global Round 11 A-F题解

很久以前,我在退役之后说过要在Codeforces上与你们再见。我回来了。

先写A-E的题解,F和G之后补。先写一部分可以防止咕咕咕。

F已经补上,G的题解非常妙,我将单独开一篇来介绍。

A. Avoiding Zero

重排一列数使得前缀和始终不为0,可能无解。

题解:和为0则显然无解,否则考虑分为正数和负数两部分,将和的绝对值大的那一部分放在前面,就不会出现前缀和为0了。

B. Chess Cheater

你有自己n场比赛的结果(赢或输),输的场不扣分,赢的场得一分,如果上一场也赢再得一分。你可以修改k场比赛的结果,使得自己总分最大。

题解:显然只需要把输改为赢。那么修改完之后赢的场次就是min{cnt+k,n},其中cnt为本来就赢得的场次。

然后只需要最小化连赢的场的段数。可以通过把两段连赢之间的输改成赢来减少一段。那么只要按照连赢段之间的距离升序排序尽量消除就可以了。

C. The Hard Work of Paparazzi

有一个二维平面,从一点(x1,y1)走到另一点(x2,y2)所花的时间为|x1x2|+|y1y2|。有n个事件,第i个在时刻ti在点(xi,yi)发生。你时刻0(1,1),问最多参与多少事件。事件发生时刻严格递增。|xi|,|yi|500,n105

题解:比赛时居然没想到...老了老了。考虑朴素dpfi表示参与i号事件时之前最多参与了几个事件。普通的一次转移是O(n)的,但考虑如果时间差大于2|x|就肯定能到了,因此前面最多只有O(|x|)个事件是需要逐一判断的。复杂度优化为O(n|x|)

D. Unshuffling a Deck

你有一个长度为n的排列p,每次可以将其分割为若干段,段内顺序不变,所有段之间顺序反转。给出不多于n次这样的操作将原排列排序。

题解:记录k是排列中的第ak个。如果对k=1,2,,n1,都有ak<ak+1就排完了。否则找到某一个ak>ak+1k

k+1之后连续递增的一段为[ak+1,pos](即这个区间内pi=iak+1+k+1),将排列分割为[1,ak+11],[ak+1,pos],[pos+1,ak],[ak+1,n]四段,用题中操作,操作完毕后ak+1=ak+1,即kk+1连在了一起,同时不会破坏任何已经连在一起的对。不断重复上述操作即可。

##E. Xum

黑板上初始有一个奇数,每次可以选黑板上两个数(可重复),再写出它们的和或异或和,重复若干步写出1。限制比较宽松。

题解:我的做法是非标准的做法。考虑用线性基判定是否可以通过异或得到1,先加和几次自身扩充一下线性基,之后每次随机从线性基中得到两个数取和加入,不久就会出解。对于2k+1的情况会比较苛刻,要先得到较大的倍数加入线性基中。

F. Boring Card Game

桌上有1,2,,6n标号的6n张连续牌,Alice和Bob玩游戏轮流取3张,Alice先取,每次取出位置连续的三张牌并将上下两堆牌合并。给出Alice最终拿到的所有牌的标号,复原一种可能的游戏过程,保证有解。n200

题解:

先考虑问题的弱化版:取消轮流取的限制,允许某人反复取三张牌,先判断这个条件下是否有解。

那么考虑一个贪心:从左到右扫描牌,逐一加入栈中,如果加入后栈顶出现三张属于同一个人的牌,就视为进行了一次取走操作,将这三张牌弹出。

如果贪心算法最终能将栈清空,显然就得到了一组合法解。现在来进一步证明如果弱化版问题有合法解那么栈一定被清空。

对取牌轮数n用数学归纳法。 n=0时显然成立。 假设n=k时成立。n=k+1时,对某种有解的情况,我们随意考虑它的某一个解,这个解的第一步取走的必定是标号连续的牌,设为k,k+1,k+2。如果我们先打破贪心规则取走这三张牌,由数学归纳法,剩下的牌可以通过贪心构造一个解。 进一步转化,可以发现如果将之后的若干不依赖于k,k+1,k+2三张牌被取走的前提就能取走的牌先于k,k+1,k+2被取走,也是合法的。因此我们换一种打破规则的方式,改成在k,k+1,k+2中的一些牌置于栈顶并可以取走时,如果并非k,k+1,k+2这一组合就不取走,直到k,k+1,k+2都出现在栈顶才取走它们(此时栈顶可能有45张属于同一人的牌),也能在之后合乎贪心的过程给出一个解。 最后,由于k,k+1,k+2是连续的,假设我们保留了本来可以取走的a,b,k不取走,k+1,k+2必定马上到来并将k带走,此时栈顶留下a,b,但是如果我们合乎规则操作,直接取走a,b,k,栈顶就剩下k+1,k+2,由于这些牌的归属者相同,对于之后的过程来说,除了标号k+1,k+2a,b没有本质区别,因此原来能得出解此刻仍然可以得出解。a,k,k+1的情况也是类似的。而此时是完全符合贪心规则的。因此也就证明完毕了。

因此原问题有解的必要条件是栈能够清空,也就是得出一种弱化版的方案,现在再来分析一下该方案中每一组牌之间的依赖关系。可以得知,如果我们让三张牌对应到包含这三张牌编号的最小区间,那么任何两个区间之间只有无交和包含两种关系,因此可以建立一个森林,树中祖先的区间包含所有后代的区间。对于这三张牌,显然只有其子树对应的三张牌组取完才可以取。不难发现,对一组三张牌,尽管其后代中可能存在归属者相同的牌组,但由贪心的性质其儿子对应的归属者都是与自己的不同的。

重新考虑轮流取的限制,我们对森林的操作就变成了:只有所有叶子都已经被取走的节点可以被取走,且必须Alice的牌的点和Bob的牌的点轮流取走。考虑是否存在这样一个取走的序列。

首先,最后一组取走的牌一定是森林中某棵树的根。因此,如果所有根都是Alice的牌,就一定无解。那么下面只要说明森林里有一棵树的根属于Bob,就一定能找到一组解。

要取Alice的节点时,假设没有Alice的节点作叶子,那么所有Alice和某个儿子Bob节点配对。但是Bob节点至少有一个根,不满足条件,因此有Alice叶子节点,随意取一个即可。

而要取Bob的节点时,此时Bob的节点多一个。分两种情况:Bob的根只有一个和有多个。 如果有多个,假设没有Bob叶子,就令每个Bob点和某儿子Alice点配对,而Alice点少一个,必不可行。又由于Bob根多于一个,取走一个并不影响“存在至少一个Bob根”这一性质,因此随便取。 如果只有一个,那么再分类: 如果这个点有儿子,本来就不可取,直接利用结论随便取走一个叶子即可。 如果这个点没有儿子,且除了它以外没有别的树,它就是最后一个点,显然可以取走。如果没有儿子且还有别的树,一定是以Alice为根,不考虑这个点后的讨论和Alice相似,一定可以找到另一个Bob叶子。