代码托管到第三方平台上。
NOI2021 题解
D1T1 轻重边
水题
D1T2 路径交点
卡常的屑水题
考虑 (k=2) 的情况,每种路径方案都可以使用一个排列来描述,排列的逆序对数量就可以用来描述交点数。
因此,设矩阵 (Min R^{n_1 imes 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)) 就是答案。顺向思考,考虑任意一种路径方案,必然可以被描述为:首先,从 (2sim k-1) 的每一层中选择一个大小为 (n_1) 的子集,接着就化归到了 (n) 相等的情况,最终我们需要对所有的子集方案求和;可以发现这就是 Cauchy-Binet 公式的形式,因此我们的猜想是正确的。
本题有亿点卡常,不建议写成矩阵乘法,建议写成类似于 DP 的形式,最终复杂度即为 (O(Tn_1sum m))。
D1T3 庆典
还不错的题目。
简单转化:题目中“可能经过 (u)”等价于“既能从 (s) 到达 (u),也能从 (u) 到达 (t)”。
首先考虑 (m=n-1) 的部分分,不难论证得出此时图的形态必然是一棵外向树。对于普通的点,它们仅能从祖先的点到达,仅能到达子树内的点。而题目给出的 (k) 条边仅仅会影响 (2k) 个点的可达性与到达性,其余的点的可达性、到达性仍然可以”借用“祖先的点和子树的点来描述。
这样,我们不难想到,最终可以经过的点就可以被描述为 (2(k+1)) 个关键点之间的某些链的并集。合法的链即”从 (s) 可以到达链头,且从链尾可以到达 (t) 的链“。注意到 (k) 很小,因此可以暴力 Floyd 求出传递闭包,接着枚举每条链,最后做一个树上链并即可。
还需要注意,新加入的 (k) 条边也可以被算作合法的链,但是显然这样的链只有端点有效,因此打一下标记即可。
最后解决 (m ot=n-1) 的情况,将强连通分量缩点之后,题目的性质在新图上仍然满足,缩点后直接跑。
小结:注意图的形态,缩点后保持树形;注意答案的形态,一定是链并。
复杂度可以做到 (O(nlog_2n+qk^3))。
D2T1 量子通信
不错的乱搞题目,正好戳中我的痛点。
由于 (kle 15),因此有变化的部分会很少;同时,如果我们将一个单词划分为 (16) 段,每段长度即为 (16),那么 (k) 次修改最多会带来 (15) 段变化,也即,必然会有一段保持不变。因此对于询问串,我们可以枚举保持不变的一段,并检查在枚举段相同的单词中是否有差异不超过 (k) 的单词。
由于字典中的单词随机,因此每一段中,某种情况的单词期望个数为 (frac{4 imes10^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=egin{bmatrix}p_k\q_kend{bmatrix},M_k=egin{bmatrix}a_k&1\1&0end{bmatrix}),则 (F_k=M_kF_{k+1})。
注意到这个转移与 (a) 相关,而为了维护操作序列的变化,我们最好是将 W
和 E
直接用矩阵来描述。
容易发现 W
其实就是矩阵 (egin{bmatrix}1&0\1&1end{bmatrix});而考虑 E
操作,当 (a) 的最后一个元素不为 1 的时候,E
等价于矩阵 (egin{bmatrix}1&0\-1&1end{bmatrix}egin{bmatrix}1&1\1&0end{bmatrix}egin{bmatrix}1&1\1&0end{bmatrix}),而当 (a) 的最后一个元素为 1 的时候,这个矩阵乘上以后得到 (egin{bmatrix}1&1\1&0end{bmatrix}egin{bmatrix}1&0\-1&1end{bmatrix}egin{bmatrix}1&1\1&0end{bmatrix}egin{bmatrix}1&1\1&0end{bmatrix}=egin{bmatrix}1&0\1&1end{bmatrix}egin{bmatrix}1&1\1&0end{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_jle n-max Ple frac{n}{2}),其中 (Psubseteq {0,1,2,dots,n-1},exist pge frac{n}{2},pin 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_jle k) 的机器人的贡献。
DP 结束后还需要计算最大值之外的位置的贡献,用好 (c) 即可。
这部分复杂度为 (O(m2^{frac{n}{2}}+n^22^{frac{n}{2}}))。
将两个做法结合在一起即可得到正解。
小结:在降低复杂度的过程中,精细的分析是很有必要的,有时候需要借助比较暴力的预处理,不过在本题中仍需要进一步分析;此外,本题的复杂度平衡依托于当包含的元素都靠前时,容斥集合包含的位置较少;当包含的元素靠后时,有效的机器人 (r) 较小,出现这样的 (min) 限制的时候需要注意是否可以平衡复杂度。