Codeforces Round #740 (Div. 1, based on VK Cup 2021 - Final (Engine)) 题解
A - Charmed by the Game
首先对于 Alice serve first 的情况而言,Alice、Borys 的 serve 次数分别为 \(p=\lceil \tfrac {a+b}{2}\rceil, q = \lfloor\tfrac{a+b}{2}\rfloor\),并设两者 break serve 对方的次数分别为 \(x\in [0, p], y\in [0, q]\)。于是显然 \(a=(p-x)+y, b=x+(q-y)\)。
然后枚举从 \(0\to p\) 枚举 \(x\),解方程得到 \(y\)。如果 \(0\le y\le q\) 则 \(x+y\) 可以作为答案。最后对于 Borys serve first 同理搞一遍即可。这是官方题解做法,比我写的容易些。
B - Up the Strip
考虑 \(f(i)\) 表示到达 \(i\) 的方案数,那么根据题意有两种转移。第一种前缀和优化比较显然,但第二种直接做的话是整除分块,这部分总复杂度为 \(O(n\sqrt n)\),通过 \(4\cdot 10^6\) 的数据比较困难。
但是我们反过来,对于 \(x\) 去更新 \(x\) 之后的位置,那么相当于需要枚举倍数 \(dx\)。对于一个 \(d\),我们相当于对 \(f(dx) \sim f(d(x+1)-1)\) 全部加上 \(f(x)\)。差分一波即可。复杂度调和级数,小常数 \(O(n\log n)\)。
C - Bottom-Tier Reversals
观察次数限制是 \(5n/2\),不妨猜想一波每确定一对数花费 \(5\) 次操作。由于我们每次翻转一个前缀,那么对于较大的数理应优先处理,因为固定了的大数必然在后面,不会为之后的操作所影响。
还有一个限制就是,一次操作只能对偶数长度翻转,那么对于无解的判断:对于位置 \(i\),其上的数值 \(x\) 与 \(i\) 的奇偶性不同。若存在如此的 \(i\) 则直接无解。
考虑当前要操作一对数字 \(k, k-1\),而 \(k+1\sim n\) 都已在对应的 \(k+1\sim n\) 位置上。接下来的方向是让 \(k-1, k\) (注意左右顺序)贴一块,这样就能一口气转到前端,然后直接目标要求位置上。可以发现一个小套路就是扔到开头,然后想到哪就到哪。
考虑如何贴一块。还是套路地先找到 \(k\),转到头上,然后找到 \(k-1\) 让 \(k\) 转到其前一个。不是先找 \(k-1\) 的原因就是因为偶数长度翻转的限制。贴上之后,由于那个偶长限制我们故意空一个再转到前面,可以发现必然可以做到空一格,反之就是在 \(k\) 转到前面之前 \(k-1\) 是第一个,而 \(k-1\) 为偶数,是上面的无解情况。剩下还有两次操作:翻转前 \(3\) 个,最后转到 \(k-1,k\) 位置上,一共 \(5\) 次。
显然最后操作下来 \(1\) 一定在第一个位置,于是做完了。
D - Top-Notch Insertions
考虑最后插入排序完毕后,得到一个数列,其间相邻两个由小于号或小于等于号连接。若有 \(c\) 个小于号,那么答案即为 \({n+c-1\choose n}\)。
如果说直接模拟插入排序,使用平衡树维护符号。一个数被插入到最前端,相当于在前面加一个 \(<\),否则就是在对应位置删除原有符号,以 \(\le, <\) 两个符号替代之。如果说没有被移动那么在末尾添加一个 \(\le\)。
直接做的话复杂度和 \(n\) 有关,而多组数据下 \(n\) 的总和可以很大。考虑 \(\le\) 的个数可能达到 \(O(n)\),而 \(<\) 的规模只有 \(O(m)\)。那么我们直接维护 \(<\) 就可以了。这样做复杂度 \(O(m\log m)\)。
E - Down Below
大概许多人都在赛时想了一个看似很假很不负责任的做法,然而一看 Tutorial 发现正是赛时的这个做法。包括我(捂脸)。
二分答案算是一个比较平凡的思路了。考虑对于一个初始 power,慢慢扩展自己已经打通的范围。最大的限制是不能立刻往回走,这要求我们走出一个路径,满足其从已扩展的顶点出发,构成一个“\(\rho\)” 形(走着走着发现到了一个自己刚刚走到的位置)或者以一个已扩展顶点结束。然后将整条路径并入已扩展点集并更新 power。
注意到这个过程一次至少给我们增加 \(1\) 个已扩展顶点,这个过程最多执行 \(n\) 次。接下来就是如何找到这样一条路径的问题。直接应用 DFS/BFS 找环的算法,在实质上将环由两段从出发点开始,分别合法的路径拼接。由于单独而言,对于一条合法路径,反过来不一定合法,因此一眼看这个“分别合法”就好像是假的。但实际上完全不假。
小证一下(实在没看懂官方题解写的,自己 YY 一个):
- 对于一条路径 \(p\),如果它合法,则必然存在一个断点满足断开可以成为两条合法路径。因为 \(p\) 的两个端点就刚好满足这条件。这保证我们必然搜得到,如果实际存在的话。
- 设 \(s, t\) 是已扩展点集中的两个点,作为新路径的端点。现在我们已经有 \(s \leadsto x, t\leadsto x\) 两条路径。考虑为什么拼起来必然合法。设走过 \(s\leadsto x\) 后 power 为 \(k_1\),路径本身走过需要最低 \(t_1\) 的初始 power。同理对 \(t\leadsto x\) 定义 \(k_2, t_2\)。如果 \(t_1 \ge k_2\),那么 \(t\leadsto x\) 走过后无法直接走过去,然而我们发现倒着必然可以,因为 \(k_1\ge t_1\ge k_2\ge t_2\)。另一种对称的情况是同理的。其他的情况就是随便选一个方向都可以。这保证了我们一旦搜到,那就是靠谱的路径。
最后就没啥了。注意搜索时的细节,不要搜出一个已扩展点集内部的环,具体实现可以带一个标记,表示是否经过至少一个未扩展顶点。
复杂度 \(O(nm\log a)\)。
F - Strange Sort
我们尝试将“排好序”这个条件进行拆解:\(\in [1, n)\),满足所有 \(\le x\) 的在左侧,\(> x\) 的在右侧。换句话说,设 \(\le x\) 的为 \(0\),其他的为 \(1\),那必须 \(0\) 全部在左边,\(1\) 全部在右边。这样我们可以将其转化为 01 序列的排序问题。
考虑计算一个 01 序列的排序次数。这等价于所有 0 的“排到正确位置所需的时间”的最大值。设 \(b_i\) 为第 \(i\) 个 0 排好需要的次数,\(m\) 为当前所有 0 的个数。
- 对于已经排好的 0,\(b_i=0\)。
- 对于一个未排好的 0,由于第 \(i\) 个 0 只有在第 \(i-1\) 个 0 排好之后,才能排上。通俗地讲就是可能会被“卡一下”。但不管怎样我们有,对于第 \(i\) 个 0,必然会比上一个排好的次数再多一次,即,\(b_i\ge b_{i-1}+1\)。
- 设第 \(i\) 个 0 之前存在 \(k_i\) 个 1,那么这些 1 每一个都对应一个“从第 \(i\) 个 0 前换到第 \(i\) 个 0 后”的事情。一次这样的事情对应一次排序。设第 \(i\) 个 0 在位置 \(p_i\),则 \(b_i\ge k_i+(p_i\bmod 2)\),因为第一次迭代对于奇数位置的 0 相当于是浪费的。
我们发现一个未排序的 0,如果它距离前面的 0 特别近,可能会被它卡一下;或者如果离得比较远,那来不及被卡,排序次数就取决于和 1 的交换了。那么得到了如下式子:
考虑到 \(b_m\) 等价与总排序次数,结合上式可得:
相当于一个后缀的 \(\max\)。不过直接维护这个 \(k_i+(p_i\bmod 2) +(m-i)\) 的话不是很好做,因为涉及动态插入和奇偶分类。不妨尝试着对应到原序列上去:设当前 0 的位置为 \(i\)(取代原来的 \(p_i\) 和 \(k_i+i\)),这个 0 是所有 0 中从左到右的第 \(rk_i\) 个(取代原来的 \(i\)),那么有:
现在可以用线段树维护了。\(i+(i\bmod 2)\) 在建树时就算好,\(m - 2rk_i\) 可以动态维护:对于一个新插入的在 \(t\) 处的 0,我们将 \([t, n]\) 区间全体减一,\([1, t)\) 全体加一即可。答案是除了已经排好的位置(不能算进去)外的最大值。注意在未插入 0 的位置其值是未定义的,那可以在初始是加上一个 \(-\infty\),在插入时加回来作为“激活”,这样就不受这些未定义位置影响了。
本文来自博客园,作者:-Wallace-,转载请注明原文链接:https://www.cnblogs.com/-Wallace-/p/sol-cf-740.html