「CEOI2011」选做

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) 的平凡转移,只需要考虑一人新加进来的情况,判断前一状态是否满足被分的所有组别都达到了最大人数,表达式:

[G_i gets G_{i-1} + [G_{i-1} * F_{i-1} = i - 1] ]

对于另一种转移,新加进了一个队伍,显然有转移:

[G_i gets max{ G_j , i - j} ]

由于是构造题,只需要记录每次新加队伍的区间即可,即在第二种转移时记录下标 (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

原文地址:https://www.cnblogs.com/Ax-Dea/p/14499118.html