当前位置: 首页 > news >正文

P11983 笔记

非人类题,思维链跟我的 OI 生涯一样长(

题意

有一个长度为 \(N\) 的序列 \(A\)\(M\) 次询问 \((L_i, R_i)\),定义序列 \(B\)\(B_i = \max_{j = L_i}^{R_i} A_j\),现在你需要重排 \(A\) 使得 \(B\) 的字典序最大。

\(N, M \le 10^5\)

思路

先想有无多项式做法~

朴素暴力

字典序问题的一个经典做法就是:对于每个 \(B_i\),从大往小枚举 \(B_i\) 的取值,再 check 能否得到。欸?但是仔细往后推推就能发现,如果想要优化这个做法,就会有巨大的后效性,寄!

那就换一个角度:从大往小枚举取值,要让取这个取值的 \(B_i\) 下标集合 \(\{i\}\) 字典序最小,这样也能得到正确答案。

于是设 \(c_v = \sum_{i = 1}^n [A_i = v]\),从大往小枚举 \(v\),并尝试给下标最小的区间赋值成 \(v\)。从前往后枚举区间 \(L_i, R_i\),每次 check 加进来 \(i\) 后,用 \(c_v\) 个点能不能使每个区间都包含至少一个数,若行就 \(B_i \gets v\),否则删掉 \(i\) 后继续往后做。用形式化的语言描述,设 \(f(S)\) 表示 \(S\) 包含的区间中最小点覆盖数量,每次判断 \(f(S \cup \{[L_i, R_i]\})\) 是否 \(\le c_v\),是就加入 \([L_i, R_i]\),否则跳过。

求解区间点覆盖的最小数量是经典贪心,将区间按 \(L\) 排序之后贪心放右端点就行了,复杂度 \(O(M)\)(每次加区间时插入排序)。

在求完 \(i\) 的答案后从序列中删除所有 \(B_i = v\) 的区间,这样下一次求答案就不会有问题。

总复杂度可以均摊到 \(O(M^2)\),可以通过 Sub 1,就不至于爆 \(0\) 了(。

优化

优化的方向有两个:

  1. 能不能通过一些性质,确定区间被加入的情况(比如一些区间一定被加,或一定不被加)?
  2. 通过数据结构优化或找特殊性质,优化掉求区间点覆盖的复杂度?

先从 1 入手,容易观察到被加入的区间一定是 一段前缀 与 后面零散的区间。而这段前缀的 \(f(S)\) 一定 \(< c_v\),后面零散的区间的 \(f(S)\) 一定 \(= c_v\)

那就考虑先求出来这段前缀吧,朴素的想法是二分,但这很容易被卡满了,需要优化。这时就有一个 Trick,叫倍增二分,用于搞一些均摊的东西。

那为什么能优化这个题呢?首先我们讲讲暴力的复杂度是怎么分析到 \(O(M^2)\) 的,我们设最后 \(S\) 中的 \(B_i\) 变成了 \(v\),那么对 \(f(S)\) check 的复杂度是 \(O(|S|)\) 的,这一轮的总复杂度就是 \(O(M |S|)\),由于 \(S\) 会在下一轮删除,故 \(\sum |S| = M\),于是总复杂度就是 \(O(M^2)\) 的。

倍增二分的流程是什么呢?首先对 \(2^0, 2^1, 2^2\) 的前缀 check,假设终点是 \(l\),就能求出 \(2^l\) 前缀的 \(f\)\(< c_v\) 的,然后在 \([2^l, 2^{l + 1})\) 这个区间二分,总复杂度就是 \(O(l \cdot 2^l)\) 的,而 \(|S|\) 的大小至少是 \(2^l\),那这个复杂度就一点问题没有,均摊下来 \(O(M \log M)\)(提前将前 \(2^{l + 1}\) 个区间排序,这样少一只 \(\log\))。

接下来处理那些零散的区间,由于这时 \(c_v = f(S)\),所以我们只需要看加入 \([L_i, R_i]\)\(f(S)\) 是否变化即可。这个怎么 check 呢?

那我们考虑维护一下每个点的位置,这样就能快速看一个区间能否包含这个点了。

具体而言,先按 \(L_i\) 从小到大,能放就放 \(R_i\) 做一遍,求出 \(c_v\) 个点每个点的位置,第 \(i\) 个点的位置记为 \(y_i\)。再按照 \(R_i\) 从大到小,能放就放 \(L_i\),求出第 \(i\) 个点的位置 \(x_i\)。那么第 \(i\) 个点的取值区间就是 \([x_i, y_i]\)。(这应该是很好理解的,就不证了)

所有区间 \([x_i, y_i]\) 应当是无交,且满足 \(y_i < x_{i + 1}\) 的。考虑加入区间 \([L, R]\)\([x_i, y_i]\) 的影响:

  • \([L, R]\) 与任何 \([x_i, y_i]\) 都无交,这时不能加入 \([L, R]\)
  • \([L, R]\) 包含了某个 \([x_i, y_i]\),那么 \([L, R]\) 加入不影响 \([x_i, y_i]\) 的取值。
  • \([L, R]\) 与恰好一个 \([x_i, y_i]\) 有交,此时将 \([x_i, y_i]\) 更新为 \([\max(L, x_i), \min(R, y_i)]\) 即可。
  • \([L, R]\) 与两个 \([x_i, y_i]\) 有交,这时不能急着对某个 \([x_i, y_i]\) 取交集(因为有后效性),我们需要等待某个 \([x_i, y_i]\) 因后面的区间 \([L', R']\) 改变后,使 \([L, R]\) 只与其中一个区间有交时,再去做改变。具体地,用 setpriority_queue 都能维护。

但是这样还是避免不了我们要扫一遍所有区间的尴尬处境,但可以通过分析上面的性质,继续优化下去。

对于每个区间 \([x_i, y_i]\),找到编号最小的和 \(i\) 相交的区间 \([L_j, R_j]\)。在所有区间中找到编号最小的之后,删除它,并继续松弛所有 \([x_i, y_i]\),此过程可用优先队列维护。

怎么找呢?可以用线段树维护,对于区间 \([L_j, R_j]\),给它完全覆盖的区间打上 \(j\) 的标记,接着 \([x_i, y_i]\) 就在线段树上所有遍历过的区间取标记的 \(\min\) 即可。

于是总复杂度 \(O(M \log M)\),代码应该非常难写啊。

http://www.rkmt.cn/news/74295.html

相关文章:

  • MILVUS Docker 容器化部署指南
  • 2026年北京市大兴区农村自建房推荐榜,图南建房宝领衔 六家家实力公司赋能乡村宜居生活。
  • 三极管/MOS管组成电源的开关电路
  • c++设计模式
  • 2025年12月恒温恒湿试验箱,高低温试验箱厂家最新推荐:电子元件测试适配与选购建议
  • HT-LFCN-113+成都恒利泰国产替代
  • 2025年震动盘推荐厂家TOP5:个性化定制与实力供应商全解
  • PHP 特性知识点扫盲:从基础到核心,快速掌握关键特性
  • CF166E-Tetrahedron
  • Android Camera性能分析 录像Buffer Path详解
  • KylinOS- V10-SP3-aarch64信创软件安装-openssl-openssh
  • 2025年度北京质量好的办公家具公司推荐:办公桌供应商哪家好
  • 2025年五大精密零部件电镀制造厂排行榜,新测评精选精密零部
  • Java 基础避坑与原理:Scanner、泛型与 ArrayList
  • 深入解析:二叉树、动态规划与链表学习
  • 2025年内蒙古十大钢结构工程设计公司推荐:钢结构工程设计公
  • 2025资质齐全的品牌策划企业TOP5推荐:美御品牌策划实力
  • 2025年比较好的MF库均化设备/IBAU库均化设备TOP品牌厂家排行榜
  • 2025年质量好的球化回火炉/密封箱式回火炉TOP实力厂家推荐榜
  • 中国宝宝肌肤护理产品怎么选?2025年最新市场分析与专业品牌推荐
  • 2025年哈尔滨诚信的汽车贴膜专业公司推荐:看哪家技术可靠?
  • 2025年耐用的6通道测力称重工业型变送器厂家最新推荐排行榜
  • 2025年质量好的循环式提升机/托盘提升机厂家推荐及选购指南
  • 广东惠算GEO:实现零点击获客的AI优化引领者
  • 2025年河南靠谱污水检查井供应商推荐,专业矩形检查井生产厂
  • AiStudio才是Gemini模型的编程真身!
  • 2025年知名的中空板厂家最新权威实力榜
  • 2025年靠谱的净化铝材/圆弧净化铝材实力厂家TOP推荐榜
  • 2025年评价高的不锈钢三节轨厂家最新热销排行
  • 从 ArrayListint 报错这个现象出发,串联起 Java 基础