CodeForces Round 968 (Div. 2) 记录
CodeForces Round 968 (Div. 2) 记录
赛时做到了 D2,Rnk 544。
A
判断首尾字符是否相等即可。
B
观察样例可知,答案是中位数偏右的那个。
证明的话,每次操作可以相当于 Alice 删除一个旁边有数比它大的数,Bob 删除一个旁边有数比它小的数,然后 Alice 必然删除前 \(\lfloor\frac n2\rfloor\) 小的数,Bob 删除前 \(\lfloor\frac n2 \rfloor\) 大的数,剩下的数就是排名在 \(\lfloor \frac n2 \rfloor + 1\) 的数了。
C
观察可知如果两个字符形成 good pair,那么它相等或一定包含一个子串,满足把连续的字符段缩成一个字符后能缩成 ABC 或 ABA 的形式。
相等的贡献是固定的,所以我们要让 ABC 尽量多,也就是我们要尽量让相邻字符不同。那么每次将当前除去上次填的字符中的众数填进去即可。
D1
考虑对一个数操作两次,那么 \(x\) 会变成这个序列填上最小的未出现过的数后的 \(\operatorname{mex}\)。
称对 \(i\) 操作两次得到的数是 \(Mex(i)\),操作一次得到的数是 \(Erase(i)\)。
那么在 D1 中,我们一定能把所有小于最大的 \(Mex(i)\) 的数变成最大的 \(Mex(i)\)。
然后大于这个数的答案是它本身,等差数列算一下即可。
D2
如果有一对不同的 \((u, v)\) 满足 \(Mex(u) = Erase(v)\),则若手上有 \(Erase(u)\),就能得到 \(Erase(v)\) 进而得到 \(Mex(v)\)。有多条路径,考虑建图,对出现上面情况的连边 \((v, u)\)。
然后最简单的想法是直接 dp 一下,设 \(f(i)\) 表示 \(i\) 能够变成的最大值。注意到我们可以把任意数变成任意 \(Erase\),所以把 \(f(i)\) 的初始值设为 \(\max(MaxErase, i)\),对每个点枚举出边并用 \(f(i)\) 转移。
但是这是错的,样例 2 就能把这个做法 Hack 掉。
然后我们注意到如果有两个不同的数 \(i, j\) 满足 \(Erase(i) = Erase(j)\),那么我们可以将所有数先操作一次 \(i\) 变成 \(Erase(i)\) 然后再让它变成 \(f(i)\)。所以用所有多于一个值的 \(Erase\) 的最大值更新一下所有数的 \(f\) 即可。
E1
将每个数分成大数和小数,满足任意大数大于所有小数。然后把数列转化成 \(01\) 串,\(0\) 代表这个位置是小数,\(1\) 代表这个位置是大数,对于 \(0\) 和 \(1\) 内部可以钦定是从大到小排序的。设 \(0\) 的数量是 \(x\),\(1\) 的数量是 \(y\),满足 \(1\) 在 \(0\) 前面的下标对的数量是 \(z\),则答案是 \(\dfrac {x(x - 1)}2 + \dfrac {y(y - 1)} 2 + z\)。
那么题目的条件转化成对于每个条件要求的区间,要满足所有 \(0\) 都在 \(1\) 前面。
那么考虑 dp。设 \(f(i, j)\) 表示前 \(i\) 个数有 \(j\) 个 \(1\) 的方案数。
枚举到区间右端点时考虑这个右端点有几个 \(1\) 应该就行了。
因为区间不重,每个数最多被算一次转移,所以时间复杂度是对的。
E2
考虑把所有区间并起来。
假设有个这样的东西

那么实际上意味着只属于绿色线段的那部分一定要是 \(0\),只属于蓝色线段的部分一定是个 \(1\),中间的部分是个新的集合。
用优先队列将左端点排序后每次取队首两条线段并,并用差分维护下每个点是否需要为 \(0\) 或 \(1\) 即可。在 dp 转移的时候要加一点细节就没了。
F
这条件巨强,还是个最优化问题,看似特别不可做好吧。
用到的是一个叫 color-coding 的算法(or trick?),之前没写过这个,受教了。
考虑 \(b\) 的所有数值域很小的时候怎么做,例如,值域是 \([1, m]\)。
状压 dp。设 \(f(i, S, j)\) 表示前 \(i\) 个数必选 \(i\),已经选过 \(b\) 的值的集合是 \(S\),当前 \(a\) 的最大值是 \(j\) 取到的最优解。
有转移:\(f(i, S, a_i) = \max _{l < i, k \le a_i, S' \cap \{b_i\} = \varnothing } f(l, S', k)\)。
这个可以树状数组维护前缀 \(\max\) 优化转移。
然后 color-coding 一下,把所有的 \(b_i\) 随机映射到 \([1, m]\) 以内后跑 \(T\) 次状压 dp 取最优解。
因为只要题目中选择的 \(m\) 个 \(b_i\) 都映射成了不同的数就能取到最优解,所以单次状压 dp 取到最优解的概率是 \(\frac {m!}{m^m}\)。当 \(T = 300\) 时,得不到最优解的概率约为 \(7.9 \times 10 ^{-6}\),这是可以接受的。
第一维一滚就没了。
实际上是对每个 \(S\) 维护一个树状数组就行了。
- 警钟长鸣,写树状数组的时候如果在函数里传入 vector 一定要加 &,不然单次修改 / 询问时间复杂度会被卡成 \(O(n)\)。

浙公网安备 33010602011771号