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