A. Acronym
枚举每个单词判断即可。
B. Baggage
考虑两个包裹分别从 u 运到 v,中途没有同时运送两个包裹,则方案形如:
- 包裹 1 u→a1,空手 a1→u,包裹 2 u→b1,空手 b1→a1,包裹 1 a1→a2,空手 a2→b1,包裹 2 b1→b2,……,包裹 1 ak→v,空手 v→bk,包裹 2 bk→v。
可以发现这样的方案可以重新排列成:
- 包裹 1 u→a1→a2→⋯→ak→v。
- 空手 v→bk→ak−1→bk−2→⋯→a1→u。
- 包裹 2 u→b1→b2→⋯→bk→v。
因此代价不小于 2dis1(u,v)+dis0(v,u),其中 disc(x,y) 是从 x 到 y,只能经过容量不少于 c 的边的最短距离。
而 2dis1(u,v)+dis0(v,u) 显然是一个合法方案,因此只需将 u 到 v 连上距离为 2dis1(u,v)+dis0(v,u)、容量为 2 的边,然后求容量 等于 2 的最短路即可。
时间复杂度 O(n3)。
C. Cows
二分答案,转化为判定是否能够在 x 分钟内吃完所有的草。
按照 i 从小到大的顺序,维护如下的状态:考虑下标在 [i,n] 中的牛,且满足下列状态之一
- 存在不超过 2 个时间区间,牛 i−1 会在这些时间区间内帮牛 i 吃草。有两种情况:
- 如果在时间 t 吃完了所有了牛 i 的所有草,则牛 i 可以在 [t,x] 时间内帮牛 i+1 吃草。
- 否则,设剩余的草的数量为 a,则牛 i+1 需要在 [x−a,x] 时间内帮牛 i 吃草。
- 存在一个时间区间 [l,r],牛 i 需要帮牛 i−1 吃草。有两种情况:
- 如果牛 i 自己能够在 l 时间之前吃完所有草,设吃完草的时间为 t,则牛 i 可以在 [t,l] 和 [r,x] 时间帮牛 i+1 吃草。
- 否则,设在 l 时刻剩余的草的数量是 a,则牛 i+1 需要在 [l−a,l] 时间内帮牛 i 吃草。
如果最终牛 n 不能吃完所有的草则说明答案大于 x。
时间复杂度 O(nlogH)。
D. Diminishing Fractions
分数的分母显然不超过 M=lcm{1,2,…,n},而分子最小是 1,因此可能的最小值是 1/M。我们考虑通分,在 modM 意义下构造 1,然后只需减去整数部分即可(因为已知分子是 1,可以直接用浮点数计算)。
设 ≤n 的所有极大素数幂分别为 pe11,pe22,…,pekk,则 M=∏ki=1peii。现在我们想要找到 ai∈[0,peii) 满足 (∑ki=1ai(M/peii))modM=1。
这可以通过 CRT 构造:我们希望 xmodpeii=1,所以令 ai 为 M/peii 在模 peii 意义下的逆元即可。
因为 ∑n 很大但 N=maxn 不大,我们在每组数据中分别进行求逆,则只需按照 n 从小到大的顺序维护 ∏j≠ipejjmodpeii。每次增加一个素数幂时,都可以在 O(k)=O(n/logn) 的时间内完成维护。
总时间复杂度 O(N2log2N+∑n)。
E. Express Rotations
考虑一个指向序列开头的指针,初始在 a1 之前。这样操作可以转化为指针循环向前移动、循环向后移动和删除指针之后的第一个数。
考虑设 dp(v,i) 表示删除了所有 ≥v 的数,指针的位置在 i 的最小代价。我们可以认为只有需要删除一个数时需要移动指针,因此有用的状态一定满足 ai=v,因此总状态数是 O(n) 的。
从 v+1 到 v 的转移,首先从之前所有有用的位置转移到所有 ai=v 的位置,这只需要先转移到前后相邻两个位置,然后再正反分别扫两遍更新。计算从位置 i 向后移动到位置 j 的代价,也就是计算 [i,j) 中所有 ≥v 的数的总和,可以用树状数组在 O(logn) 时间内计算。
接下来考虑删除所有等于 v 的数。可以发现指针的移动要么是先往前再往后,要么是先往后再往前。如果是先往前再往后,可以认为所有数都是在往后的过程中被删除,因此直接用指针移动的代价减去所有 =v 的数的总和来更新即可。如果是先往后再往前,因为往后移动的过程中,删除一个数不需要代价,但往前移动的过程中需要先移动到数之前再删除,所以有 v 的代价。我们可以将少的代价在往后移动的过程中计算,即从 i 移动到 j 的代价是 [i,j) 中所有 >v 的数的总和减去 v。这会导致一个问题:移动的代价可能是负数,导致一直在环上绕圈。这是因为,我们只有在第一次删除一个数的时候会带来总代价的减少,但直接在环上转移忽略了这个限制。一个解决方案是使用单调队列,限制只能往后移动 cntv−1 次。
时间复杂度 O(nlogn)。
F. Frogs
考虑计算 p=n 的答案。令 bi=ai+1−ai(下标都是 modn 意义下的),即青蛙 i 要追的青蛙和它坐标的差。如果 bi≥0,则青蛙 i 会向右跳,否则会向左跳。考虑 bi 的变化,当 bi≥0 且 bi+1<0 时会减去 2k,当 bi<0 且 bi+1≥0 时会加上 2k。可以发现,在有限轮之后,所有的 bi 都会落入 [−2k,2k) 内。此后 {bi} 一定会进入一个循环,我们希望判断在一个循环内,青蛙的坐标是否不变。注意到当所有 bi∈[−2k,2k) 时,bi 的符号(负数还是非负)只和上一个时刻 bi+1 的符号有关,因此在循环中负数的个数是始终不变的,因此我们只需判断负数的个数是否等于非负数的个数。
我们只需判断是否有 n/2=∑[bi<0]=12k∑(bimod2k−bi)。注意到 ∑bi=0,而 ∑(bimod2k) 是常数,因此只需判断是否有 ∑(bimod2k)=∑((ai+1−ai)mod2k)=nk 即可。
对于所有的 p 计算答案,也只需要在 p 增大的时候维护这个和。
时间复杂度 O(n)。
G. Game MPO
将所有的 M 和 P、O 和 O 连边,则只需从所有大写字母开始 BFS 即可得到最终状态。
H. High Jump
最优策略可以表示成 a1<a2<⋯<ak,依次挑战高度 a1,a2,…,ak。分数的期望是 pa1a1+pa1pa2(a2−a1)+pa1pa2pa3(a3−a2)+⋯。令 a0=0,这个式子也可以写成 f(i)=(f(i+1)+(ai+1−ai))pai+1,答案即为 f(0)。
考虑从后往前 DP,则 dp(i)=maxj>i{(dp(j)+j−i)⋅pj},可以用凸包优化转移。
时间复杂度 O(n)。
I. Imbalanced Teams
显然最大值等于前 k 大的和减去前 k 小的和。在确定了选择的数的可重集后,只需乘上对应的组合数即可。注意如果两个队伍有相同的数,还需要计算分组的方案数,并且当所有数全相等时,两组是本质相同的,方案数需要除以 2。
时间复杂度 O(n)。
J. Just Zeros
考虑维护 f(S) 表示翻转的行的集合是 S 的情况下,还需要多少步能够将所有数变成 0。也就是翻转行后,每一列的 min{c,1+h−c} 之和。通过 f(S) 可以在 O(2h) 时间内计算答案。
如何在操作后维护 f(S):
- P 和 K 操作都只会影响一列,可以对每个 S 重新计算该列的贡献。
- R 操作只需将 f(S) 和 f(S⊕{i}) 交换。注意需要打一个第 i 行取反的标记,在另外两种操作中需要用到。
时间复杂度 O((w+q)2h)。
K. Kindergarten Square
通过两行的差可以求出 w,而 h 越大越好,然后判断是否满足条件即可。
L. Looping RPS
考虑对 s∞i 建立 Trie,则三个人形成一个环当且仅当它们在同一个点的三个不同子树内。因此建立 Trie 后可以直接枚举 LCA 计算贡献。
建立 Trie 分为两步:排序,然后计算相邻串的 LCP 并建立笛卡尔树。
难点主要在于排序,直接按照 a+b<b+a 比较可能导致时间复杂度变为 Ω(n|s|)。我们希望比较两个串的复杂度是 O(min{|a|,|b|}),则总复杂度为 O(∑|si|logn)。不妨设 |a|≤|b|。如果 a 不是 b 的前缀则可以直接比较,否则我们需要求 b 和 b[|a|:] 的 LCP,这可以通过预处理每个串的 Z 函数后 O(1) 得到。
时间复杂度 O(∑|si|logn)。