「NOI 2021」题解
代码托管到第三方平台上。
NOI2021 题解
D1T1 轻重边
水题
D1T2 路径交点
卡常的屑水题
考虑 \(k=2\) 的情况,每种路径方案都可以使用一个排列来描述,排列的逆序对数量就可以用来描述交点数。
因此,设矩阵 \(M\in R^{n_1\times n_1},M_{ij}=[(i,j)\in E]\),那么自然而然地得到 \(k=2\) 时答案为:
考虑 \(n\) 相等的情况。由于 \(k>2\) 时,各层的逆序对为叠加关系,因此各层的行列式乘法时 \(-1\) 的指数就会相加,满足系数要求;同时,将行列式相乘也相当于枚举了每一种可能的方案,因此可以得到答案:
最后考虑 \(n\) 不相等的情况,根据 \(n_k=n_1\) 的限制不难想到 \(\det(\prod_{j=1}^{k-1}M_j)\) 就是答案。顺向思考,考虑任意一种路径方案,必然可以被描述为:首先,从 \(2\sim k-1\) 的每一层中选择一个大小为 \(n_1\) 的子集,接着就化归到了 \(n\) 相等的情况,最终我们需要对所有的子集方案求和;可以发现这就是 Cauchy-Binet 公式的形式,因此我们的猜想是正确的。
本题有亿点卡常,不建议写成矩阵乘法,建议写成类似于 DP 的形式,最终复杂度即为 \(O(Tn_1\sum m)\)。
D1T3 庆典
还不错的题目。
简单转化:题目中“可能经过 \(u\)”等价于“既能从 \(s\) 到达 \(u\),也能从 \(u\) 到达 \(t\)”。
首先考虑 \(m=n-1\) 的部分分,不难论证得出此时图的形态必然是一棵外向树。对于普通的点,它们仅能从祖先的点到达,仅能到达子树内的点。而题目给出的 \(k\) 条边仅仅会影响 \(2k\) 个点的可达性与到达性,其余的点的可达性、到达性仍然可以”借用“祖先的点和子树的点来描述。
这样,我们不难想到,最终可以经过的点就可以被描述为 \(2(k+1)\) 个关键点之间的某些链的并集。合法的链即”从 \(s\) 可以到达链头,且从链尾可以到达 \(t\) 的链“。注意到 \(k\) 很小,因此可以暴力 Floyd 求出传递闭包,接着枚举每条链,最后做一个树上链并即可。
还需要注意,新加入的 \(k\) 条边也可以被算作合法的链,但是显然这样的链只有端点有效,因此打一下标记即可。
最后解决 \(m\not=n-1\) 的情况,将强连通分量缩点之后,题目的性质在新图上仍然满足,缩点后直接跑。
小结:注意图的形态,缩点后保持树形;注意答案的形态,一定是链并。
复杂度可以做到 \(O(n\log_2n+qk^3)\)。
D2T1 量子通信
不错的乱搞题目,正好戳中我的痛点。
由于 \(k\le 15\),因此有变化的部分会很少;同时,如果我们将一个单词划分为 \(16\) 段,每段长度即为 \(16\),那么 \(k\) 次修改最多会带来 \(15\) 段变化,也即,必然会有一段保持不变。因此对于询问串,我们可以枚举保持不变的一段,并检查在枚举段相同的单词中是否有差异不超过 \(k\) 的单词。
由于字典中的单词随机,因此每一段中,某种情况的单词期望个数为 \(\frac{4\times10^5}{2^{16}}\approx 8\);此外,计算差异数可以用 __builtin_popcountll
做到 4 次运算,因而复杂度为 \(O(n+q)\),其中 \(n\) 的常数约为 64, \(q\) 的常数约为 512。
小结:一定要多多注意小数据的处理方式,在这道题中就根据较小的修改次数和较长的长度,运用鸽巢原理大幅缩减所需检查的字符串的数量(这应该是查找类题目的重要思路)。
D2T2 密码箱
容易发现 \(f\) 计算的是一个连分数:\([a_0;a_1,a_2,\dots,a_n]\)
考虑递推计算,设 \(f_k=[a_k;a_{k+1},a_{k+2},\dots,a_n]=\frac{p_k}{q_k}\);特别地,边界 \(f_n=\frac{1}{a_n}\)。
那么递推关系为:
也即:
这组递推式有两个作用:
第一,根据递推式可以发现 \(\gcd(p_k,q_k)=\gcd(p_{k+1},q_{k+1})\),在边界处 \(\gcd(p_k,q_k)=1\),因此中途结果均保持既约性质,不需要约分;
第二,递推式是线性的,这表明递推过程可以用矩阵来描述;设 \(F_k=\begin{bmatrix}p_k\\q_k\end{bmatrix},M_k=\begin{bmatrix}a_k&1\\1&0\end{bmatrix}\),则 \(F_k=M_kF_{k+1}\)。
注意到这个转移与 \(a\) 相关,而为了维护操作序列的变化,我们最好是将 W
和 E
直接用矩阵来描述。
容易发现 W
其实就是矩阵 \(\begin{bmatrix}1&0\\1&1\end{bmatrix}\);而考虑 E
操作,当 \(a\) 的最后一个元素不为 1 的时候,E
等价于矩阵 \(\begin{bmatrix}1&0\\-1&1\end{bmatrix}\begin{bmatrix}1&1\\1&0\end{bmatrix}\begin{bmatrix}1&1\\1&0\end{bmatrix}\),而当 \(a\) 的最后一个元素为 1 的时候,这个矩阵乘上以后得到 \(\begin{bmatrix}1&1\\1&0\end{bmatrix}\begin{bmatrix}1&0\\-1&1\end{bmatrix}\begin{bmatrix}1&1\\1&0\end{bmatrix}\begin{bmatrix}1&1\\1&0\end{bmatrix}=\begin{bmatrix}1&0\\1&1\end{bmatrix}\begin{bmatrix}1&1\\1&0\end{bmatrix}\),施加上以后恰好等价于“先去掉最后一个元素,再给最后一个元素 +1,再在末尾添加一个 1”,也就是给倒数第二个元素 +1。
因此直接用平衡树维护矩阵积即可,细节有亿点多。
小结:从部分情况入手,逐步推广的思路很好用;尤其是在本题中,E
的操作看起来构造性很强,其实也暗示它很有可能就是某一特殊情况简单推广后的结果。
D2T3 机器人游戏
非常棒的题目,质量很不错
样例 2 的解释贴心地给出了容斥计算的解释,直接模拟可以得到一个 \(O(2^nn^2m)\) 或者 \(O(2^nnm)\) 的容斥做法,这里就不详细解释了。
但是这个做法还需要优化。不难发现对于每个格子的四种操作:不变/赋 0/赋 1/取反 构成了一个群,以下我们分别用 0/1/2/3 表示这四种操作。
我们只需要考虑每个格子被操作覆盖的情况即可计算出方案数。在较差的复杂度中,我们可以直接预处理每种情况的方案数;为了优化,我们需要细致分析。假如一个格子同时被 0,3 覆盖,或者同时被 1,2 覆盖,那么它只能输入输出都为空,因此方案数为 1;假如一个格子被 0/3 其一覆盖,同时被 1/2 其一覆盖,那么它除空外只有一种方案,因此方案数为 2;在其它情况下,方案数均为 3。
需要注意,如果某个格子并未被容斥集合中出发的每机器人次覆盖住,那么该格子便隐式地被 0 覆盖。
那么,对于任意容斥集合 \(P\),使用 unsigned
我们不难处理出操作 \(o\) 影响到的格子的集合 \(f_{P,o}\),按照上面的分析处理出不同情况的位置集合计算即可。
如此我们得到了 \(O(2^nm)\) 的容斥。
为了方便描述,设 \(r_j\) 表示机器人 \(j\) 影响到的格子个数,也即字符串中 R
数量 +1。
注意到极限数据为 \(n=32\),恰好为 \(16\) 的两倍,这启示我们折半处理容斥集合。对于仅包含左边 \(16\) 个位置的容斥集合,我们可以直接枚举并计算;对于包含右边 \(16\) 个位置中任意一个的容斥集合,我们注意到此时贡献非 1 方案数的机器人必然满足 \(r_j\le n-\max P\le \frac{n}{2}\),其中 \(P\subseteq \{0,1,2,\dots,n-1\},\exist p\ge \frac{n}{2},p\in P\)。
由于每个位置仅会受前 \(r_j\) 个位置影响,因此我们可以枚举 \(P\) 中最大值后直接 DP,状态 \(f_{i,S,0/1}\) 表示前 \(i\) 个位置,其中 \([i-\frac{n}{2}+1,i]\) 的选择情况为 \(S\),在 \([0,i-\frac{n}{2}]\) 中无/有选中的位置的情况下,容斥的结果。其中每个位置的贡献也可以预处理,\(c_{S,0/1,k}\) 表示对于某一位置,若 \([i-\frac{n}{2}+1,i]\) 的选择情况为 \(S\),在范围外无/有选中的位置的情况下,所有 \(r_j\le k\) 的机器人的贡献。
DP 结束后还需要计算最大值之外的位置的贡献,用好 \(c\) 即可。
这部分复杂度为 \(O(m2^{\frac{n}{2}}+n^22^{\frac{n}{2}})\)。
将两个做法结合在一起即可得到正解。
小结:在降低复杂度的过程中,精细的分析是很有必要的,有时候需要借助比较暴力的预处理,不过在本题中仍需要进一步分析;此外,本题的复杂度平衡依托于当包含的元素都靠前时,容斥集合包含的位置较少;当包含的元素靠后时,有效的机器人 \(r\) 较小,出现这样的 \(\min\) 限制的时候需要注意是否可以平衡复杂度。