CF1969E Unique Array 题解

CF1969E Unique Array

题意

给你一个长度为 n n n 的数组 a a a。定义 a a a 的子数组是其连续子序列之一(即数组 a l , a l + 1 , . . . , a r a_l, a_{l + 1}, ..., a_r al,al+1,...,ar ,其中 l l l r r r 是某两个整数,使得 1 ≤ l < r ≤ n 1 \le l \lt r \le n 1l<rn )。如果一个整数在子数组中出现的次数正好是一次,那么这个子数组就是合法的。

你有一种操作,每次可以将任意一个 a i a_i ai 替换为任意整数,求最小的操作次数时的 a a a 的所有子序列都合法。

解析

引理1:

假设将 a x a_x ax 替换成 y y y,若 y y y 都不同于 a a a 中的所有元素,那么凡是包含 x x x 的区间都变得合法。

证明显而易见,因为 y y y 在包含 x x x 的区间中都只出现了一次。

那么有了引理1,相当于每次操作相当于将数组 a a a x x x 处断开,将两端分开考虑。

我们就可以得到一个显然的贪心策略,将遍历 1 → n 1\to n 1n,当遍历到 i i i 时,前缀数组由合法变得不合法,那就在 i i i 处断开。

证明也很简单,因为 i i i 是最晚断开且满足合法的下标,即在 i i i 之后断开会变得不合法,在 i i i 之前断开一定不会最优(因为断开的数少了)。

接下来就是如何快速查询前缀数组是否合法。

假设 l s t a i lst_{a_i} lstai 表示 a i a_i ai 上一次出现的位置, n x t a i nxt_{a_i} nxtai 表示 a i a_i ai 下一次出现的位置,显然 a i a_i ai 在区间 [ l , r ] [l,r] [l,r] 中唯一出现的必要条件就是 l ∈ ( l s t a i , i ] l\in (lst_{a_i},i] l(lstai,i] r ∈ [ i , n x t a i ) r\in [i,nxt_{a_i}) r[i,nxtai)

我们还很容易发现,对于一个 a j a_j aj,若 n x t a j < i nxt_{a_j}<i nxtaj<i,左端点 l ∈ ( l s t a j , i ] l\in (lst_{a_j},i] l(lstaj,i] 必然合法。

关键是我们还是从左往右遍历的,也就是每次新加入一个 i i i 时,我们只需要判断以 i i i 为右端点的区间是否都合法,根据上面的结论,我们只需要一个数组 x x x,其中 x j x_j xj 表示区间 [ j , i ] [j,i] [j,i] 中有多少个数是唯一的。

当我们遍历到 a i a_i ai 的时候,区间 [ l , r ] [l,r] [l,r] l ∈ ( l s t l s t a i , l s t a i ] , r = i l\in(lst_{lst_{a_i}},lst_{a_i}],r=i l(lstlstai,lstai],r=i 中的 a i a_i ai 变得不在唯一,则对这段区间 − 1 -1 1;区间 [ l , r ] [l,r] [l,r] l ∈ ( l s t a i , i ] , r = i l\in(lst_{a_i},i],r=i l(lstai,i],r=i 变得唯一,则对这段区间 + 1 +1 +1

∃ j ∈ [ 1 , i ] \exist j\in[1,i] j[1,i],若 x j = 0 x_j=0 xj=0 则不合法。

主体思路就完了,最后我们发现 x x x 数组可以用线段树维护,最后时间复杂度为 O ( n log ⁡ 2 n ) O(n\log_2n) O(nlog2n)

代码太丑了,不放了。

  • 14
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值