Codeforces Round 804(div 2)

C.The Third Problem
题目大意
给你一个序列 aaaa 是一个 [0n1][0\to n-1]排列
问能够造出多少种序列 bb,其中 bb 也是一个 [0n1][0 \to n-1] 的排列
并且必须满足,bb 所有的子区间 [l,r][l, r]
mex(bl,br)=mex(al,,ar)\text{mex}(b_l\cdots, b_r) = \text{mex}(a_l, \cdots, a_r)

算法分析
因为 bb 是一个排列,所以 bb 的所有子区间的 mex\text{mex} 值一定会取遍 {0,1,,n1,n}\{0, 1, \cdots, n-1, n\}
于是我们可以一个一个数考虑,对于数 x[0,n1]x \in [0, n-1],考虑它有几个位置可以放置?
最后把答案都乘起来就可以

不妨设当前正在考虑的数为 xx
并且使得 [0x1][0\cdots x-1] 这些数都出现过的最小区间是 [l,r][l, r],我们有一些性质

  • [l,r][l, r] 中的所有子区间(不包括 [l,r][l, r])的 mex\text{mex} 值只能在 {0,1,,x1}\{0,1, \cdots, x-1\} 中取
    并且除了 {0,1,,x1}\{0, 1, \cdots, x-1\} 这些数所在的位置之外,剩下的数都 >x1> x-1
    只要 {0,1,,x1}\{0, 1, \cdots, x-1\} 这些数的位置不变,剩下的数换成任意一个 >x1> x-1 的数
    所有子区间的 mex\text{mex} 值都不会改变
  • {0,1,,x1}\{0, 1, \cdots, x-1\} 这些位置呢?实际上这是一个子问题
    考虑 [0x2][0\cdots x-2] 所有数都出现的最小子区间 [l,r][l', r'],如上分析

这样就启发我们从 x[0n1]x \in [0 \to n-1] 递推考虑
不妨设当前正在考虑的数是 xx,首先必须找到最小的满足 [0x1][0\cdots x-1] 都出现的区间 [l,r][l, r]

  • xx[l,r][l, r] 区间外面,不妨设它的位置是 p(x)p(x)p(x)>rp(x) > r
    那么此时 bbxx 的位置不能动
    因为 mex([r+1,p(x)1])=x\text{mex}([r+1, p(x)-1]) = x,如果将 xx 移动到 p(x)1\text{p}(x) - 1
    那么 mex([r+1,p(x)1])=x+1x\text{mex}([r+1, p(x)-1]) = x+1 \neq x,不符合条件
  • xx[l,r][l, r] 区间中,lp(x)rl \leqslant p(x) \leqslant r
    经过我们上面的分析,x>x1x > x-1
    所以 xx 可以放置在除了 {0,1,,x1}\{0, 1, \cdots, x-1\} 所在位置之外的任意一个位置
    xx 放置位置的方案数为 (rl+1x)(r-l+1 - x)

D. Almost Triple Deletions
题目大意
给你一个数组 a[1n]a[1\cdots n],每一次操作,如果 aiai+1a_i \neq a_{i+1},可以将 ai,ai+1a_i, a_{i+1} 都删掉
删掉之后剩下的数拼接起来
经过若干次这样操作之后,最后要使得数组中所有元素都相同
那么最后的数组最大长度是多少

思路分析
由于操作之后数组中所有元素都相同,n5000n \leqslant 5000,所以可以枚举操作完成后,数组中相同元素的值 xx
一开始可以对 xx 出现的所有位置打表,记 xx 出现的第 ii 个位置是 fx(i)\displaystyle f_x(i)
只考虑 xx 出现的位置,从 i1ii-1 \to i

对于区间 [fx(i1)fx(i)][f_x(i-1)\cdots f_x(i)],如果中间的数 [fx(i1)+1,fx(i)1][f_x(i-1)+1, f_x(i)-1] 能全部消去
那么就存在转移 fx(i)=fx(i1)+1f_x(i) = f_x(i-1) + 1
其中 fx(i)f_x(i) 表示第 iixx 这个位置,得到的数组的最大长度

这样就启发我们用 dpdp 来实现
dp(i)dp(i) 表示 ii 位置的这个数最终保留下来,并且作为序列结尾,能得到的序列最大长度
那么存在 dp(i)=max(dp(j)+1)(aj=ai, 1ji1)dp(i) = \max(dp(j) + 1) \quad (a_j = a_i, \ 1 \leqslant j \leqslant i-1) 的转移
当且仅当 [j+1,i1][j+1, i-1] 中的数可以消去

要想保留 aia_i,那么 dpdp 的起点一定是找到第一个 x=aix = a_i 所在的位置 ss
dp(s)=1dp(s) = 1,然后递推
一开始的时候,所有点的 dpdp 值都是 00,先预处理一下
如果 [1i1][1\cdots i-1] 的前缀可以消去,那么 ii 就可以作为 dpdp 的起点,dp(i)=1dp(i) = 1
接着按上面的方法递推就可以

接下来的难点就是,什么时候 [l,r][l, r] 中的元素可以全部消去?不妨设 [l,r][l, r] 中的元素个数为 nn

  • nn 必须是偶数,这根据题意很容易发现
  • 实际上消去的充要条件是,对 [l,r][l, r] 中的每一个数 xx,都能找到一个 yxy \neq x 与它匹配
    对于出现次数最大的数 xx
    xx 如果出现次数 >n/2> n/2,必然有某个 xx 找不到匹配,否则一定是可以的

证明如下,如果出现次数最多的数 xx 出现的次数都 n/2\leqslant n/2,那么最坏的情况
就是序列一段都是 xx,最前面的 xx 能消去,那么一整段都可以消去
这是可能的,因为我们可以贪心地考虑 [2,n/2][2\cdots, n/2]
这些 xx 从后往前依次和 [n/2+1n][n/2+1 \cdots n] 这些 yxy \neq x 配对删除
再来看看充分性
如果有一个数 xx 出现次数 k>n/2k > n/2,那么其他元素的个数是 nkn - k
因为其他元素都要被删除,所以还剩下无法匹配xx 个数是 n2(nk)>0n - 2(n-k) > 0
这显然是不符合全部删除的要求的

最后计算答案的时候,因为每一个位置 ii 都可能作为序列的结尾
根据之前的分析,dp(i)dp(i)ii 这个位置保留下来并且作为序列结尾,能够得到的最大长度
如果 [i+1,n][i+1, n] 这一段能够完全删除,那么就可以对所有这样的 dp(i)dp(i) 取一个 max\max 就是答案

E. Three Days Grace
题目大意
给你一个数组 a[1,n]a[1, n],可能有重复元素,每一个元素的值都在 [1,m][1, m] 之间
接下来你可以
aa 中选出一个元素 xx,然后对 xx 进行分解,x=pq, (p,q>1)x = p\cdot q, \ (p, q > 1)
然后把 xxaa 中删除,再把 p,qp, q 加入集合 aa
问经过若干次这样的操作之后,数组的 max(ai)min(ai)\max(a_i) - \min(a_i) 最小是多少

先来看一个经典问题
给你一个数组,要求你求一个区间 [l,r][l, r],使得这个区间中 max(ai)min(ai)\max(a_i) - \min(a_i) 最大或最小

这个问题我们一般是枚举最小值 xx,单调栈求出左边第一个 >x> x 的元素位置 ll
以及右边第一个 >x> x 的元素位置 rr,那么 [l+1,r1][l+1, r-1] 区间的最小值都是 xx

接下来只需要用 ST\text{ST} 表或者是线段树求出 [l+1,r1][l+1, r-1] 的最大值 maxvmaxv 即可
然后用 maxvxmaxv - x 来更新全局的 ansans,即可在 O(nlogn)O(n \log n) 的复杂度内完成问题求解

本题也可以类似考虑
枚举 ii 作为序列最小元素 minvminv 时候的情形,问题等价于
对于每一个 iiii 可以由 x[ii, i(i+1), i(i+2)]x \in [i\cdot i, \ i \cdot(i+1), \ i \cdot (i+2) \cdots ] 分解而来

ii 作为 xx 分解得到的最小的因子,我们要在 xx 分解出来的,并且 i\geqslant i 的因子中
找到尽量小的那个因子,记这个尽量小的因子是 dpi(x)dp_i(x)

尽量小的,并且比 ii 大的因子记为 resres

这样对于每一个 xx22 种决策

  • xx 分解出一个 ii 来,不往下继续分解了,res=dpi(x)res = dp_i(x)
  • x/ix/i 继续往下分解,枚举 x/ix/i 的分解情况
    for j(x/i)\textbf{for} \ \forall j \mid (x/i)jj 作为 x/ix/i 的因子,必须满足
    (1)j>i, j=[i,i+1,]\textbf{(1)}\quad j > i, \ j = [i, i+1, \cdots]
    (2)j\textbf{(2)}\quad jx/ix/i 分解出来的最小因子

这样就有转移

dpi(x)=min(dpi(x),jminjdpj(x/i)),j\displaystyle dp_i(x) = \min(dp_i(x), \forall j \min_{j} dp_j(x/i)), j 满足上述两个条件

那么这个问题很容易用 O(n2)O(n^2) 枚举求解,一边求解的时候一边用 dpi(x)idp_i(x) - i 更新答案即可
下面考虑如何优化

注意到我们这里用 dpj(x)dp_j(x') 来更新 dpi(x)dp_i(x),其中 jij \geqslant i
如果我们 jj 从大往小去遍历,相应的 dpj+1(x)dp_{j+1}(x) 就可以实时维护
换句话说,当 j+1jj+1 \to j 的时候,dpj+1(x)dp_{j+1}(x) 的值实际上是维护了 <dpj+1(x),dpj+2(x),>\left< dp_{j+1}(x), dp_{j+2}(x), \cdots \right>

由此,从大往小去遍历 ii,上面的式子就可以实时维护了
具体来说用旧的 dp(x/i)dp(x/i) 来更新当前的 dp(x)dp(x)

那最后一个问题就是如何计算答案,可以用一个 set\textbf{set} 维护 dpdp 值,一开始所有数 dp(x)=xdp(x) = x
将其都放入 set\text{set}
对于 for i[maxv1]\textbf{for} \ \forall i \in [maxv \to 1]
执行 dp(x)=min(dp(x),dp(x/i))dp(x) = \min (dp(x), dp(x/i)) 的时候,我们要这样做
(1)将原来的 dp(x)dp(x)set\text{set} 中删除
(2)更新 dp(x)=min(dp(x),dp(x/i))dp(x) = \min(dp(x), dp(x/i))
(3)在 set\text{set} 中插入新的 dpdp

当遍历 iminvi \leqslant minvminvminv 是原序列的最小值
我们就可以用 set 中的最大值i\text{set 中的最大值} - i 来更新答案了

Educational Codeforces Round 131

D. Permutation Restoration
题目大意
你有一个排列 aa,现在你可以根据 aa 得到数组 bb,其中 bi=iaib_i = \displaystyle \left \lfloor \frac{i}{a_i} \right \rfloor

现在你忘了排列 aa 是啥,给你一个数组 bb,要求从数组 bb 构造出数组 aa

原问题可以转换成为,已知 i,bii, b_i,构造出 aia_i 满足

ibi+1<aiibi\displaystyle \frac{i}{b_i+1} < a_i \leqslant \frac{i}{b_i},不妨记 L(i)=ibi+1+1,R(i)=ibiL(i) = \displaystyle \frac{i}{b_i + 1} + 1, R(i) = \frac{i}{b_i}

下面问题转换成
给你 nn 个数,第 ii 个数的取值区间是 [L(i),R(i)][L(i), R(i)],要求你在每一个区间内选一个数来构造排列
其中要求,所选的数不能重合,这是贪心算法中很典型的活动选择问题

在活动选择问题中,我们是这样执行贪心策略的
对所有区间按照右端点排序,然后依次检查每一个区间
对于每个区间,我们选择最小的,并且未被选过的数,那么这个问题也类似

这个问题与区间选择问题不同的是,可能多个 a(i1),a(i2),a(i_1), a(i_2), \cdots 有着相同的左端点
可以先打表处理 has(x)={i1,i2,}\text{has}(x) = \{i_1, i_2, \cdots\},表示这些 ii 都以 xx 作为值域区间的左端点

然后我们遍历 for x[1n]\textbf{for} \ \forall x \in [1\cdots n]
对于 has(x)\text{has}(x) 中的 <i1,i2,>\left<i_1, i_2, \cdots \right>,根据活动选择问题中的分析
这些 ii 我们理论上都可以赋值成 ai=xa_i = x,但我们应该取 R(i)R(i) 尽量小的那个 ii 赋值成 xx

算法实现上,用一个二元组 (R(i),i)(R(i), i) 来表示
那么我们应该把 xx 值,赋给尽量小的 R(i)R(i) 所对应的那个 ii
将二元组放入 set\text{set} 中,然后将 set\text{set} 最开头那个元素对应的 ii 赋值成 xx
赋值完成后就将其删除,这样就保证了每个元素只会被赋值一次

E. Text Editor
题目大意
你有一个文本编辑器,你本来想要打一个目标串 tt,包含 mm 个小写字符
但是你现在打了一个文本串 ss,包含 nn 个小写字符并且 mnm \leqslant n

现在你有以下几种操作,一开始光标在 ss 的最后一个字符后边
left\text{left} 将光标左移 11 位,left\text{left} 将光标右移 11
Home, End\text{Home, End} 分别将光标置为文本串的最开始(第一个字符前面)和最末尾(最后一个字符后边)
Back\text{Back} 删除光标前的字符并将其删除

下面问从 ss 变到 tt,最少要执行上述操作中的一种,执行多少次?
如果不能从 sts \to t,输出 1-1

算法分析
首先所有的操作都不会在 ss 中引入新的字符,所以如果 tt 中有一些字符 ss 中没有
那么一定不可以