CF1342 简要题解
因为 F 咕了好久,所以现在才写题解的屑(
- A
如果 \(2a\geq b\),显然先选 \(\min(x, y)\) 次 \(b\),否则不选 \(b\)。
- B
如果 \(t\) 只有一种字符,直接输出 \(t\) 即可,周期为 \(1\)。
否则周期 \(\geq 2\)。由于 \(|s|\leq 2\cdot |t|\),可以令 \(s=(01)^{|t|}\),可以发现每两位中选一位出来,必然可以找到子序列 \(t\)。
- C
不难发现,\(x\bmod a\bmod b\) 以及 \(x\bmod b\bmod a\) 的值,只和 \(x\bmod (ab)\) 的值有关。因此对每组数据,只需要预处理 \(x\in [0, ab)\) 的前缀和,就可以 \(O(1)\) 回答询问,复杂度 \(O\left(t(q+ab)\right)\)。
- D
如果一个 testcase
还可以容纳一个大小为 \(x\) 的 array
,那么它必然还可以容纳一个 \(\leq x\) 的 array
。因此,最优的方案显然是先在每个 testcase
里尽可能地多放大的。设 \(a_i\) 表示大小为 \(i\) 的 array
数量,则 testcase
的最小数量为 \(\max_{i=1}^k(\lceil\frac{\sum_{j=i}^{k} a_j}{c_i}\rceil)\)。
放的时候只需要按顺序贪心,但是要注意一点是,如果多个连续的 \(c_i\) 相同,则应该将他们看作相同的 array
,否则,如果在较大的 \(i\) 处填满了 \(c_i\),对于较小,但是 \(c_i\) 相同的 \(i\),可能会向下遍历 \(O(n)\) 个 testcase
才能找到第一个合适的位置。如果将连续的 \(c_i\) 看作相同的,则复杂度可以由均摊来保证。
- E
(写完后发现写的好长啊……我是萌新,实锤了)
首先考虑,如何在 \(n\times n\) 的棋盘内放 \(n\) 个车,并让每个格子都处在车的攻击范围内。实际上这等价于,每一行都有至少一个车,或每一列都有至少一个车。证明可以考虑,如果存在至少一行、一列都没有车,那么它们的交点处的格子不可能被覆盖。由于只有 \(n\) 个车,我们可以将 “至少” 替换为 “恰好”,不难发现一样成立。
不难发现,如果 \(k=0\),则任意一种方案都形如 \((1, p_1), (2, p_2), \ldots, (n, p_n)\)。并且对于每一个排列 \(p\),这样的方案都是合法的,因此 \(k=0\) 时答案恰为 \(n!\)。
当 \(k\ne 0\) 时,我们发现两个条件是互斥的,因此只能选择满足其中一个。发现对于任意一种满足每行恰好一个车的条件的方案,将它沿主对角线翻转后,恰好对应了一种满足每列恰好一个车的方案,因此只需要对其中一个条件求解,乘以 \(2\) 就是答案。
现在要求解的问题是,在 \(n\times n\) 的棋盘上,每行放一个车(可以发现,互相攻击的车一定在同一列),恰好有 \(k\) 对车可以互相攻击的方案数。
换个思路想想,对于一种确定的方案,如何判定有多少车可以互相攻击。对于一个列,如果它放了 \(a_i>0\) 个车,那么这一列共有 \(a_i-1\) 对车可以互相攻击,否则有 \(0\) 对。可以发现,每一个非空的列都给答案贡献了一个 \(-1\),因此一个方案有 \(k\) 对车可以互相攻击,当且仅当它恰好有 \(n-k\) 列非空。
现在的问题是,将 \(n\) 个有标号的球放进 \(n\) 个有标号的盒子里,求 \(f(n, k)\) 表示恰好有 \(k\) 个盒子为空的方案数。直接求比较困难,考虑容斥。
设 \(g(n, k)\) 表示随意硬点 \(k\) 个盒子是空的,并将每一个球任意地放进没有被硬点的盒子里的方案数。显然 \(g(n, k)=\binom{n}{k}(n-k)^n\)。考虑组合意义,发现对于满足 \(f(n, i), i\geq k\) 的每种方案,会在 \(g(n, k)\) 中被算到 \(\binom{i}{k}\) 次(即,假设满足 \(f(n, i)\) 的方案选择了某个大小为 \(i\) 的盒子的子集 \(S\),那么在计算 \(g(n, k)\) 时,如果我们硬点为空的盒子集合为 \(T\),那么这种方案会被计算一次,当且仅当 \(T\subseteq S\)),所以有 \(g(n, k)=\sum_{i=k}^n f(n, i)\binom{i}{k}\)。
这里复习一下二项式反演。由基本的二项式定理,我们知道 \(\sum_{i=0}^x \binom{x}{i}(-1)^i=\left[1+(-1)\right]^x=[x=0]\)。
设 \(g_x=\sum_{i=x}^n f_i\binom{i}{x}\),则:
观察内外层枚举的上下界,不难发现实际上是 \(x\leq i\leq j\leq n\),因此可以先枚举 \(j\):
考虑内层的两个组合数的意义,它表示先从 \(j\) 个物品中选 \(i\) 个,再从选出的 \(i\) 个中选 \(x\) 个,等价于直接从 \(j\) 个中选 \(x\) 个,再在剩余的 \(j-x\) 个中选 \(i-x\) 个。因此有:
设 \(i'=i-x\),则:
左右式恰好相等。因此我们证明了第一行的式子 \(f_x=\sum_{i=x}^n (-1)^{i-x} g_x \binom{i}{x}\) 是正确的,代入本题即可得到最终答案:
- F
首先考虑一下,如果已知了一组将 \(a\) 划分为若干个子集的方案,如何判断它是否能构成合法的递增序列。
将每个子集按照权值和排序,显然不能出现两个子集权值相同。另外,按照权值和排序后,需要确定这个子集最后落脚的位置。换句话说,需要存在一种按顺序从每个子集取出一个元素的顺序,使得这些元素在原序列中的位置也是递增的。
\(n=15\) 的数据范围可以基本确定是状压 dp,然而还需要确定状态维度:
- 已用的 \(a\) 的子集;
- 最后一个子集的权值和;
- 操作次数;
- 最后一个子集中取出一个元素的位置。
如果将状态 \(1, 2, 4\) 作为维度,最小化 \(2\) 的话,状态数最少也是 \(O(n^2 2^n)\) 级别,由于转移中不可避免地枚举子集,复杂度不会低于 \(O(n^2 3^n)\)。精细实现的话可以通过本题,但是可以做到更优秀。
实际上,我们并不需要最小化 \(2\),只需要保证整个过程中 \(2\) 的值严格递增。因此,只需要预处理出 \(2^n\) 个子集的权值和并排序,按照顺序更新状态,就可以避免 \(2\) 的影响。注意有可能出现多个子集权值相等,需要将它们一起处理,防止相互影响。
因此,设 \(f_{i, S, x}\) 表示考虑了 \(a\) 的前 \(i\) 小的子集,已用状态为 \(S\),操作了 \(x\) 次时,最后一个子集中取出元素的最小位置。预处理新加入每个子集时取出元素的位置变化,就可以做到枚举子集后 \(O(1)\) 转移,总的时间复杂度为 \(O(n3^n)\)。注意到不需要显式维护 \(i\) 这一维,否则复杂度无法承受。
但是,如果不维护 \(i\),输出方案将变得相当棘手。一个可行的解决方案是,更新每个 \(f_{S, x}\) 时,将此时的 \(i\) 作为一个额外信息储存起来。更新的时候不需要删除原来储存的信息,只需要 push_back
。这样在倒推回方案的时候,由于每次选择的子集排序后的序号是单调的,只需要找到最近的合法的子集即可。由于每个 \(f_{S, x}\) 只会被更新 \(O(n)\) 次,总的空间复杂度不超过 \(O(n^2 2^n)\)。
代码比较精污,细节巨大多。