26DMYCSP-S#12
Daimayuan CSP-S 2026 Round 12
闲话
早上又起晚了,\(8:40\) 开的。
看了下四个题,T1 和 T3 是本质数数,T2 是本质构造,T4 是本质数据结构。
那我肯定开 T2,简单手玩样例得到首先要搞出 \(2^k\),然后直接用 \(2^k, 2^{k - 1}\) 造出 \(2^{k + 1}\) 状物,然后归纳构造 \(n\) 就可以做到 \(120\) 次左右的操作,又因为可以把上面的操作扩展到 \(2^k - c\) 状物,需要线性预处理 \(2c\) 大小的前缀,所以平衡一下 \(c = 8\) 是合适的,这样可以做到 \(90\) 次操作左右,肯定稳了,大概 1h10min 左右。
然后开始 T1,做了很久没有想到一个有道理的计数角度,怎么数貌似都会重或者漏。然后注意到因为可能出现 \(0\) 种食材但是若干道菜,所以应该是先选一部分人领到菜再考虑食材分配的问题。因此可以对 \(k_0, k_1\) 两个部分分别考虑,固定前者的一个子集领到菜,那么因为编号不降所以每个人领到的必定是一个子段,只需要确定大小,则可以发现每个人的贡献是 \(k_0\) 部分 \(2x\) 状物,\(k_1\) 部分 \(2x + 1\) 状物,然后总和是 \(\sum x_i = \frac{n - k_1}{2}\)。因此可以直接对子段计数,二项式反过去化简得到 \(\mathcal{O}(n)\) 的做法。大概 1h30min。
现在其实没多少时间了,前两个题都这么难那后两个肯定更吓人,选择拼部分分,T4 的分显然好拼一点,首先 \(n \leq 500\) 是送的,然后貌似 \(n \leq 8000\) 其实也是送的,实则非然,因为不一定有逆元所以没法直接打标记,但是因为操作全部在询问前面所以可以考虑猫树,这样就不存在逆元了,是 \(\mathcal{O}(n^2 + n \log^2 n + q)\) 状物,试了一下发现常数还挺小,后面基本要更进一步的思考了,我选择回去看 T3。
嗯嗯对的首先 \(A_{i,j} \neq -1\) 对应的 \((i,j)\) 视作一条边,权值是 \(x_i + x_j\),那么考虑先固定连通块之后 \(b\) 和 \(x\) 的取值数,注意到只需要看图是否为二分图,不是的话会有一部分权值按照奇环传递回来,否则没有,所以是甚么 \(\binom{m + 1}{2}^k - \binom{m}{2}^k\) 状物。那你考虑对每个连通块 DP,每次归纳地找标号最小的点对应的连通块,设大小 \(k\) 那么等价于选出 \(k - 1\) 个点,然后对联通条件算一次,再对二分图条件容斥一次,考虑先把染色带上处理每张图,只需要枚举黑点的数量,然后因为每张联通二分图内恰有 \(2\) 类合法的黑白染色,所以此时再容斥一次就求出来了。最后合并每个连通块即可。这个不是一般的难写,于是先把前面三个题交了再来写,赛后 20min 过了/kk
最后没有挂分,这是好事,\(100 + 100 + 0 + 20 = 220\),rk 32,感觉主要的问题就是 T3 这种可以一步一步推过去的题其实可以前期写一些复杂度比较高的暴力,一方面部分分很多另一方面可以直接用暴力结果反推某些系数,可能过的反而比现在快一点。
T1
tag:组合计数。
因为一个人可能吃到若干份由 \(0\) 种食材组成的菜,所以一开始要按照一个人有没有菜,有多少菜来分类,然后再考虑选一些食材进到这个人吃的菜的集合里面。
假设前 \(k_0\) 个人里面恰有 \(i\) 个人拿到菜,因为后 \(k_1\) 个人必定全部拿到菜,所以一共有 \(K = i + k_1\) 个人拿到菜。这对应 \(\binom{k_0}{i}\) 种方案数。
再考虑菜的标号以及食材的标号,因为人的编号是不降的,每个人拿到的菜必定是一个连续段,因此只需要确定每一段的长度,分配方式就完全确定了。对前 \(i\) 个人它们拿到的食材总份数可以表示为 \(2x_1, 2x_2, \dots, 2x_i\),对后面 \(k_1\) 个人可以表示为 \(2x_{i+1}+1, 2x_{i+2}+1, \dots, 2x_{K} + 1\)。去掉后 \(k_1\) 个人必须拿到的限制就有 \(\sum_{j = 1}^{K} x_j = (n - k_1)/2\)。因此总方案数可以直接插板得到是 \(\binom{(n - k_1)/2 + K - 1}{(n - k_1)/2}\)。
接下来考虑固定每个人的食材数量,则有 \(\sum_{j=1}^{K} x_j = n\),如果第 \(j\) 个人拿到了 \(y_j \geq 1\) 道菜,那么将食材数 \(x_j\) 放进这 \(y_j\) 道菜的方案数就是 \(\binom{x_j + y_j - 1}{y_j - 1}\),因此可以直接对所有满足 \(\sum_{j=1}^{K} t_j = m\) 的方案求和,利用二项式定理我们有 \(\sum_{y \geq 1} \binom{x + y - 1}{y - 1}v^{y - 1} = (1 - v)^{-x - 1}\),因此所有段对应的方案就是对所有 \(\sum_{i=1}^{K} t_i = m\) 的情况,数 \(\sum_{t} \prod_{i=1}^{K} \binom{x_i + y_i - 1}{y_i - 1} = \binom{n + m - 1}{m - K}\),这个原理就是上面说的二项式,你注意到它等价于 \((1 - v)^{-n - K}\) 对应展开式的第 \(m - K\) 项系数。因此对每个 \(K = j + k_1\) 我们只需要计算出对应的
答案即为 \(\sum_{j = 0}^{\min(k_0, m - k_1)} W_j\),需要注意的是如果 \(k_1 = 0\) 那么 \(j\) 不能取到 \(0\)。这整个东西都是可以预处理阶乘逆元然后线性计算的,时间复杂度 \(\mathcal{O}(n)\)。
T2
tag:位运算、构造、Ad-hoc。
首先有一个线性的思路,就是你考虑 \(f(x,0) = x + 1\),所以可以 \(\mathcal{O}(n)\) 地生成所有 \([0,n]\) 以内的数。
然后你注意到是位运算构造,所以对每一个数,肯定是类似于拆位然后用已知部分二进制位为 \(0\) 的信息,把 \(n\) 的二进制位逐步还原出来。因此我们首先考虑 \(2^k\) 如何被快速递推出来。假设已有 \(2^k, 2^{k} - 1\),那么可以用三次操作 \(X = f(2^k - 1,2) = 2^k - 2,Y = f(2^k, X) = 2^{k + 1} - 1, Z = f(2^k,2^{k-1}) = 2^{k + 1}\) 递推出新的 \(2^k, 2^{k} - 1\),所以可以 \(\mathcal{O}(\log n)\),常数为 \(3\) 地求出所有 \(2\) 的整次幂。这个对小的 \(n\) 可能不如直接线性生成,比如啥 \(n \leq 8\) 的都直接线性算什么的。
再来考虑如何构造 \(n\),肯定是逐位构造所以考虑归纳构造。具体地说:
- 如果当前 \(n = 0\) 那么直接返回 \(0\)。
- 否则如果当前 \(n\) 是 \(2\) 的整次幂直接返回上一步取出的对应下标。
- 否则,取出 \(n\) 的最高二进制位 \(h\),那么可以分成 \(2^h\) 和 \(r = n - 2^h - 1\) 这两个部分,所以本质上就是 \(f(2^h, r)\) 状物,前者可以直接取出,后者每次减少一个二进制位所以整个过程至多需要 \(\lfloor \log_2(n) \rfloor\) 次操作。
那么两部分结合起来,前面是 \(3\) 倍常数后面是 \(1\) 倍常数,因为很小 \(2^k\) 的生成是线性的所以还能省下两步,总共就是 \(4 \times \lfloor \log_2(n) \rfloor - 2 \leq 114\) 次操作。已经可以通过了。
但是因为这个数很极限,场上没时间细细证明会不会被怪东西卡爆,我们考虑更优的思路:注意到上面用已知的 \(2^k - 1\) 状物递推 \(2^{k+1}\) 的操作过程是可以扩展的。具体来说,我们考虑维护 \(2^k - c\) 状物,那么每层对应了 \(X = f(2^k, 2^k - c) = 2^{k + 1} - c + 1, Y = f(x, c - 2) = 2^{k + 1}\),所以不考虑 \(c\) 逐位右移的花费我们每层只需要 \(2\) 次操作。平衡一下,因为取到 \(c\) 要确保前 \(c\) 个元素以及 \(2c - 1, 2c\) 已经被递推出,所以平衡两边取到 \(c = 8\) 比较合适,此时可以 \(8\) 次操作取到 \(1 \sim 8\) 然后 \(2\) 次操作 \(f(8,6), f(15,0)\) 取到 \(15, 16\)。那么每 \(7\) 次迭代需要一次操作来恢复 \(c = 8\),至多从 \(2^4\) 倍增到 \(2^{29}\) 一共 \(25\) 层,这样的操作一共至多需要 \(3\) 次。总的操作数就是 \(10 + 2 \times 25 + 3 = 63\) 次。然后因为 \(1 \sim 8\) 已经合出来了,所以归纳构造 \(n\) 也只需要 \(29 - 3 + 1 = 27\) 次,总共就是至多 \(90\) 次。
话说这个东西再贪心优化一下可以到 \(75\) 次,但没必要了。时间复杂度 \(\mathcal{O}(\log n)\)。
T3
tag:图论、组合计数、容斥原理。
首先这个图一看就是邻接矩阵,所以考虑图论转化,即 \(A_{i,j} \neq -1\) 的部分视为一条边 \((i,j)\),边权 \(x_i + x_j\)。然后你要数的就是对任意连边方案和对应的权值约束 \((A,b)\),可能的赋权值方案数。
先考虑固定了连边方案的 \(k\) 个点的连通图,计算其边权和对应限制 \(b\) 一共有多少种可行取值。如果 \(i,j\) 对应同一组边权那么令 \(d_i = x_i - x_j\),则每条边对应都有 \(d_i + d_j = 0\)。
这个就很有交错树的结构了,如果这张图不是二分图,那么沿着奇环可以得到环上每一个 \(d_i = 0\),再通过连通性得到所有 \(d_i = 0\)。因此每组边权至多对应一个 \(x\),任取合法 \((x_i,b_i)\) 再确定边权必定不重,有方案数 \(\left(\sum_{x = 0}^{m}(x + 1)\right)^k = \binom{m + 2}{2}^k\)。
然后考虑是二分图的情况,可以直接取一个二分图划分方式 \(L,R\),那么可以任取一组特解,剩下的所有解都可以转化为,取一个使得所有 \(x_i \in [0,b_i]\) 的整数 \(t\),然后对 \(u \in L\) 有 \(x_u' = x_u + t\),对 \(v \in R\) 有 \(x'_v = x_v - t\)。因为 \(0 \leq x_i \leq b_i\) 等价于把它框在一个区间里面,所以对每一组可行的 \(x,b\),固定区间内合法的 \(t\) 最大的解作为特解,则每组特解和对应的 \(x,b\) 构成双射。因为一组解若不是最大解那么还可以对存在的连边 \((u,v), u \in L, v \in R\) 调整 \(x_u \leftarrow x_u + 1, x_v \leftarrow x_v - 1\),所以固定二分图对应的赋权值方案数为 \(\binom{m+2}{2}^k - \binom{m+1}{2}^k\)。因此问题变成,你需要求出 \(f_n, g_n\) 分别表示 \(n\) 个带标号点的连通图和二分图数量,所有大小为 \(k\) 的连通块的总权值就是 \(W_k = f_k \times \binom{m + 2}{2}^k - g_k \times \binom{m + 1}{2}^k\)。答案就是对这个东西做卷积 \(h_n = \sum_{k = 1}^{n} \binom{n}{k} W_k \times h_{n - k}\)。
所以现在问题变为求 \(f,g\)。这个 trick 是经典的,每次考虑最小标号的点对应的连通块从而做到不重不漏计数。具体来说,我们考虑求出 \(p_n\) 表示 \(n\) 个带标号点上的任意简单图数量,显然一开始有 \(p_n = 2^{\binom{n}{2}}\),然后考虑 \(1\) 号点所在连通块,大小设为 \(k\),那么等价于要从 \(n - 1\) 个点内取出 \(k - 1\) 个点,对构成连通图的情况有 \(f_{k}\),其他所有点构成任意图的情况 \(p_{n - k}\),则有 \(p_n = \sum_{k=1}^{n} \binom{n-1}{k-1}f_k \times p_{n - k}\),容斥一下 \(k = n\) 的项就得到了 \(f_n = p_n - \sum_{k=1}^{n-1} \binom{n-1}{k-1} f_k \times p_{n - k}\)。这样连通图数量就求出来了。
再考虑求二分连通图的数量,直接统计是困难的,但是你发现因为是连通的二分图,所以只有 \(2\) 种黑白染色方案,故可以直接带上黑白染色计数最后除 \(2\)。设这种图的数量为 \(q_n\),枚举黑点数目就有 \(q_n = \sum_{k = 0}^{n} \binom{n}{k} 2^{k(n - k)}\)。然后还是一样考虑点 \(1\) 所在连通块,带上两种染色的贡献就有 \(q_n = \sum_{k=1}^{n} \binom{n-1}{k-1} \times 2g_k \times q_{n - k}\),因此容斥一下 \(k = n\) 同样我们得到了 \(g_n = \frac{q_n}{2} - \sum_{k=1}^{n-1} \binom{n-1}{k-1} g_k \times q_{n - k}\)。
然后有了这两个东西就可以直接像上面说的那样 \(\mathcal{O}(n^2)\) 算答案了,总时间复杂度 \(\mathcal{O}(n^2)\)。
T4
tag:等价类分治、线段树。
\(20 \ \text{pts}\)
考虑 \(n \leq 8000\) 怎么做,因为不保证有逆元,所以无法直接对每个子矩形打标记。但是因为所有修改操作均在询问之前,所以可以考虑线段树分治维护每个询问对应的后缀及其贡献,标记永久化实现。
具体地说,将行视为时间轴做线段树分治,那么一个子矩形对应了 \(\mathcal{O}(\log n)\) 个节点上的操作。每个点上挂对应的 \((l,r,v)\),那么总共拆出来有 \(\mathcal{O}(n \log n)\) 个询问。再考虑对列维护一棵线段树,因为只需要查叶子的取值所以只需要维护每个节点对应的乘法标记。无需下传标记,只需要每次 DFS 线段树得到对应列的所有修改结果。这样即可做到 \(\mathcal{O}(n^2 + n \log^2 n + q)\)。
浙公网安备 33010602011771号