20251022
正睿 NOIP 二十连测。
B
有 \(n\) 个数 \(a_1 \sim a_n\),可以进行若干次以下操作,问对于 \(k = 1, 2, 3 \dots n\),至少需要几次操作才能删去 \(k\) 个数。
- 选择若干相同的数删去。
 - 选择若干个互不相同的数删去。
 
不难发现答案一定是一个递增的序列。令 \(b_i\) 表示 \(i\) 次操作至多能删掉几个数,那么 \(b_{i - 1} + 1\sim b_i\) 这些 \(k\) 的答案就是 \(i\)。
尝试化简两种操作。考虑将 \(n\) 个数丢尽一个桶 \(c\),\(c_i\) 表示有 \(c_i\) 个数为 \(i\)。不难发现,第一种操作为删去一个 \(c_i\),第二种操作时将所有 \(> 0\) 的数 \(-1\),尽可能让 \(c\) 数组之和最小。
因为执行 \(1\) 操作肯定选 \(c_i\) 大的删,所以可以将 \(c\) 从大到小排序
考虑枚举进行了 \(x\) 次操作 \(1\) 和 \(y\) 次操作 \(2\),首先执行的顺序是无关紧要的(都一样)。预处理一下即可快速得到还剩多少个。
这个看起来是 \(O(n^2)\),实际不然。因为枚举了 \(x\) 后,\(y\) 只需要枚举到 \(c_{x + 1}\) 即可,所以只需要枚举 \(\sum c_i\) 对 \((x, y)\) 即可。
还有一种方式,因为至多执行 \(\sqrt n\) 次 \(1\) 操作和 \(\sqrt n\) 次而操作就可以删完(否则出现了 \(\sqrt n + 1\) 个大于 \(\sqrt n\) 的 \(c_i\)),只用枚举 \(x, y \le 2\sqrt n\) 即可。时间复杂度也是 \(O(n)\) 的。
本题要想到枚举 \(x, y\) 搞出一个看似 \(O(n^2)\) 的做法,稍加分析即可变为 \(O(n)\),本人使用的第二种方式。
C
对于一个 \(1 \sim n\) 的排列 \(p\),构造一个 \(n\) 个点无向图 \(G(p)\),\(u, v(u < v)\) 之间有连边当且仅当 \(p_u > p_v\)。现在给定 \(p, q\) ,问有多少排列 \(w\) 满足 \(w\) 的字典序在 \(p \sim q\) 之间且 \(G(w)\) 是一个三分图。
\(T\) 组询问,\(T, n \le 300\)。
首先我们要明确 \(G(p)\) 是一个三分图意味着啥?
我们知道判三分图其实是没有多项式复杂度做法的(NP),一定有利用 \(G(p)\) 的一些性质。
先来找一些必要条件,如果 \(p\) 的最长下降子序列长度 \(\ge 4\),\(G(p)\) 就不是三分图。因为这形成了一个 \(k4\)(大小为 \(4\) 的完全子图)。
实际上这个条件也是充分,写个暴力可以过样例,拿到了 \(25pts\)。具体证明如下:
若最长下降子序列长度 \(\le 3\),根据 Dilworth 定理可以将 \(p\) 划分成不超过 \(3\) 个上升子序列,每个子序列染一种颜色即可(子序列内部无边)。
所以题目条件化简为有多少个 \(w\) 满足 \(w\) 的字典序在 \(p \sim q\) 之间且 \(w\) 的最长下降子序列长度不超过 \(3\)?
接下来先不考虑字典序的限制,就只有下降子序列长度不超过 \(3\) 的限制。
回想一下求 LIS 的二分做法,令 \(g_i\) 表示长度为 \(i\) 的上升子序列末尾元素最小值。\(g_i\) 是递增的,每次加入 \(x\) 找到最小的 \(i\) 满足 \(x \le g_i\) 更新即可。
因为下降子序列长度不超过 \(3\),我们只需要维护这三个数 \(g_1, g_2, g_3\) 即可,实际上只在乎每段还有几个数。可以设计出一个 DP,令 \(f_{i, j, k}\) 表示现在的下降子序列是 \([x, y, z]\),\([x + 1, n]\) 有 \(i\) 个没有选的数,\([y + 1, x - 1]\) 有 \(j\) 个没有选的数 ,\([z + 1, y - 1]\) 有 \(k\) 个没有选的数时的方案数。(\([1, z - 1]\) 不能有数)。
初始状态是 \(f_{0, 0, 0} = 1\),转移可以枚举是往哪个部分添加的,是这个部分第几个数,可以从一下几个部分转移而来:
直接做是 \(O(n^4)\) 的,变一下形可以使用前缀和优化(觉得麻烦使用树状数组也能过,我就是的)。时间复杂度优化为 \(O(n^3)\)。
再考虑字典序限制,可以先转化为字典序 \(\le p\) 的合法排列数,枚举和 \(p\) 相同的前缀和第一个不相同位置的取值 \(v\),算出此时的 \(x, y, z\) 以及每个部分有多少个数就可以直接调用 \(f\) 的取值了(\(f\) 可以预处理出来,每组是一样的。)
时间复杂度:\(O(n^3 + Tn^2)\)。
注意前缀和 \(v\) 时要判断是否合法!!
有一个类似想法的题,也是用利用二分求 LIS 的思路 DP:CF2142D(求 \(a\) 有多少个子序列的下降子序列长度 \(\le 2\),设 \(dp_{i, j, k}\) 表示前 \(i\) 个数有多少个子序列 \(g_1 = j, g_2 = k\),利用一些神奇性质转移。)
总结一下,这个题首先要”猜“出三分图的等价条件,还是经典先想必要条件。
然后利用二分求 LIS 的思想去 DP,设计出状态(得出维护什么)优化一下转移即可。
赛时写了 \(25pts\) 的暴力,然后就没想了。这个思路可以利用在有关于 LIS/LDS 长度的条件的情况。
                    
                
                
            
        
浙公网安备 33010602011771号