P9970 [THUPC 2024 初赛] 套娃
题面
定义一个集合的 是最小的不在 中的非负整数。给定一个序列 ,对于每个 ,我们按照如下方式定义 :
- 对于 的所有长为 的子区间,求出这个子区间构成的数集的 。
- 对于求出的所有 ,求出这个数集自己的 ,记为 。
请你求出序列 。
数据范围:。
题解
感觉挺难的啊,为毛过了一车人...
总体的思路是找到形如 和 这样的区间,使 ,那么我们就可以对 在 的这些 都加上 元素,将这些修改操作扫描线处理一下,然后就可以用线段树上二分的方式找最小的没有出现的元素。
现在考虑去求这样的区间。
首先是一个结论:记最小 区间表示:对于一个区间 ,不存在一个子区间 ,使 ,那么一个序列的所有最小 区间的数量是 的。
证明:对于一个满足条件的最小的 区间 , 显然满足 ,否则删任意一个不影响答案。不妨假设 ,那么有 。
此时如果还存在一个 使得 ,那么 一定在 中出现过了(不然 不会大于等于 ),那么对于一个 来说,那些比他 大,并且和 组成最小 区间的 只会出现最多 次,那么整个序列最多就是 个最小 序列。
现在我们考虑维护所有的最小 区间 ,考虑往其两边扩展,那么就是找到 左边和 右边最近的 使 ,求出其 ,那么就可以找到所有可能的最小 区间。
注意并不是一定,如 ,那么 往左扩展会到 ,很明显不是最小 区间。
对于一组最小 区间,求出其最大 区间是比较显然的,左右端点就是 左边和 右边最近的 ,在计算扩展区间的时候就已经处理出来了。
那么我们整个算法流程就是:
- 预处理出极小的 和 的区间。
- 对于每一个 区间,分别求出其距离左端点最近的 出现位置 ,和距离右端点最近的 出现位置 ,形成两个新的区间,算一下 的 ,然后丢到对应的存储 区间的
vector
里,并且将 记录下来后续处理。 - 对于每一个 ,先将删去被包含的区间,在对每一个 进行扩展。
注意这里要有一个在线求 的算法,就是 P4137 。考虑建立一个主席树,每一个节点 存的是 中最晚出现的下表,这样在查询 的时候我们就在 那一棵树上找出现时间 的最小的节点是什么。
启发
- 关于 的一个结论:一个序列的所有最小 区间的数量是 的。
- 关于求区间 的算法:主席树+线段树二分。
本文作者:qwq_123
本文链接:https://www.cnblogs.com/qwq-123/p/17935194.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步