zoukankan      html  css  js  c++  java
  • 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

    有一个二维平面,从一点((x_1,y_1))走到另一点((x_2,y_2))所花的时间为(|x_1-x_2|+|y_1-y_2|)。有(n)个事件,第(i)个在时刻(t_i)在点((x_i,y_i))发生。你时刻(0)((1,1)),问最多参与多少事件。事件发生时刻严格递增。(|x_i|,|y_i|leq 500,nleq 10^5)

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

    D. Unshuffling a Deck

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

    题解:记录(k)是排列中的第(a_k)个。如果对(k=1,2,dots,n-1),都有(a_k<a_{k+1})就排完了。否则找到某一个(a_k>a_{k+1})(k)

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

    E. Xum

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

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

    F. Boring Card Game

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

    题解:

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

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

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

    对取牌轮数(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)都出现在栈顶才取走它们(此时栈顶可能有(4-5)张属于同一人的牌),也能在之后合乎贪心的过程给出一个解。
    最后,由于(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+2)(a,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)叶子。

  • 相关阅读:
    FreeCommander 学习手册
    String详解, String和CharSequence区别, StringBuilder和StringBuffer的区别 (String系列之1)
    StringBuffer 详解 (String系列之3)
    StringBuilder 详解 (String系列之2)
    java io系列26之 RandomAccessFile
    java io系列25之 PrintWriter (字符打印输出流)
    java io系列24之 BufferedWriter(字符缓冲输出流)
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
  • 原文地址:https://www.cnblogs.com/Mr-Spade/p/13827623.html
Copyright © 2011-2022 走看看