Teams
(mathcal{O}(nlog n)) 是一个平凡的二分,来一发 (mathcal{O}(n)) 的奇妙解法。
对于第一问,设 (F_i) 表示前 (i) 个小朋友能分成的最大队伍数。
为保证无后效性并创造单调性质,需要将 (a_i) 降序排序,易证。
考虑不同转移的情况,发现转移 (F_i gets F_{j} + 1) ,当且仅当 (a_j + j = i) 。
还有一个平凡的转移 (F_i gets F_{i-1}) ,总转移数是 (mathcal{O}(n)) 级别的。
第二问,最小化最大队伍的人数,设 (G_i) ,表示前 (i) 个小朋友最大队伍的人数。
对于 (F) 的平凡转移,只需要考虑一人新加进来的情况,判断前一状态是否满足被分的所有组别都达到了最大人数,表达式:
对于另一种转移,新加进了一个队伍,显然有转移:
由于是构造题,只需要记录每次新加队伍的区间即可,即在第二种转移时记录下标 (j) 。
Code(C++): Link 。
Matching
将整个排列转化为每个值前面有几个比它大的数,可以证明对于任意一个顺序确定的序列,这样的转化是唯一的。
随后用 BIT 维护,用 KMP 算法匹配即可。
Code(C++): Link
Treasure Hunt
由于有加点操作,只能用倍增维护。
考虑 (50\%) 的数据,对于询问操作列出步骤。
先找到 LCA ,求出 (u ightarrow v) 的长度为 ( ext{dist}) ,找出更深的一条树链,若这是 (rt ightarrow u) 则记 (d = lfloor frac{dist}{2} floor) ,否则记 (d = lceil frac{dist}{2} ceil) 。
根据 (d) 向上倍增找点即可。
对于 (100\%) 的数据,发现难点在如何判断一段节点到另一段节点后出现的位置,将此也倍增维护即可。
Code(C++) : Link