「CEOI2011」选做
Teams
\(\mathcal{O}(n\log 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\rightarrow v\) 的长度为 \(\text{dist}\) ,找出更深的一条树链,若这是 \(rt \rightarrow u\) 则记 \(d = \lfloor \frac{dist}{2}\rfloor\) ,否则记 \(d = \lceil \frac{dist}{2} \rceil\) 。
根据 \(d\) 向上倍增找点即可。
对于 \(100\%\) 的数据,发现难点在如何判断一段节点到另一段节点后出现的位置,将此也倍增维护即可。
Code(C++) : Link
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步