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 1≤l<r≤n )。如果一个整数在子数组中出现的次数正好是一次,那么这个子数组就是合法的。
你有一种操作,每次可以将任意一个 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 1→n,当遍历到 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)
代码太丑了,不放了。