1 条题解
-
0
题目理解
我们有一个序列 ,要找一个最长的不含重复元素的子序列 。
如果有多个最长的,选择将奇数位置上的元素乘 后字典序最小的那个。
子任务:忽略字典序最小,只求长度
显然,最长的无重复子序列的长度 就是 中不同元素的个数。
因为每个元素最多选一次,而我们可以把每个不同元素都选上(按某种顺序)。所以:
构造 从左到右,不破坏最长性
我们已知最大长度是 ,现在要构造 ,使得它是最优的(奇数位置乘 后字典序最小)。
假设我们已经选好了 ,其中 (即最后一个选的是位置 的值)。
我们要选 ,必须保证后面还能选出 个不同的元素(包括 本身)。
关键观察
设 表示元素 在子数组 中最后一次出现的位置,如果不存在则 。
那么,我们可以在区间:
中任意选择一个位置作为 的位置。
因为如果选的位置超过 ,那么某个元素 就再也没有机会出现了,导致无法凑齐 个不同元素。
如何最小化字典序(考虑奇数位置乘 )
我们要比较的是:
所以:
- 当 是奇数时,我们希望 尽可能小(因为乘 后负得更多,字典序更小)。
- 当 是偶数时,我们希望 尽可能大。
如果候选区间中有多个相同的最优值,我们选最左边的那个,因为这样剩下的后缀更长,更有利于后续构造。
窗口单调性
随着 向右移动(即我们选的位置越来越靠后),候选区间的左边界 递增,右边界 也非递减(因为 只会变小或不变,所以最小值不会变小)。
因此我们可以用优先队列(堆)或有序集合来维护候选元素。
算法步骤
- 预处理每个值 在 中所有出现的位置(或最后一次出现)。
- 初始化当前指针 (表示已选到位置 )。
- 对于 从 到 :
- 确定候选区间 ,其中 , 是 在 中的最后一次出现。
- 如果 是奇数:在区间内选最小的值;如果 是偶数:选最大的值。若有多个相同值,选最左边的。
- 设选中的位置是 ,值 。
- 更新 ,并删除 的后续出现记录(因为它已被选过,不能再选)。
- 输出 。
时间复杂度
- 每个元素最多入堆/出堆一次。
- 使用优先队列维护最小值和最大值,。
- 总和 ,可以通过。
- 1
信息
- ID
- 6378
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者