26DMYCSP-S#6

Daimayuan CSP-S 2026 Round 6

闲话

这场真有点哈人了,AIGC 大哥放过我吧。

20min 看四个题,T1 只能操作一次翻转,看起来是不那么 Ad-hoc 的本质字符串分析题,T2 是树上的数数题,一眼树拓扑序相关,T3 咋又是树,一眼 \(\text{mex}\) 染色相关结论题,看到时限 \(3000 \text{ms}\) 释怀了,T4 神秘数据结构,不懂。

开 T1,注意到问题等价于将字符串划分为四段 \(A+B+C+D\),满足 \(B = C\) 并且 \(A + D\) 可以被消掉,那么一开始可以直接把 \(A,D\) 消掉,\(B,C\) 本质是 Trie 树上一段折返路径,直接建树做就好了。有点难调,vscode 插件还一直返回 PE,后面换了 Dev-C++ 用命令行编译 checker.cpp 才测明白(伏笔)。一共 1h 左右。

开 T2,考虑将最后剩下那个点定根,每条边定向为指向领到任务那个点,那么问题等价于一棵外向树上做拓扑序计数。对于一个根,算方案数就是树上拓扑序,即 \(\frac{(n-1)!}{\prod_{v \in \text{son}(u)} \text{sz}(v)!}\) 状物。可以定根的点必定是局部最大值,即 \(p_r \gt \max\limits_{i \in \text{N}(r)} p_i\)。所以只需要求出边对应的 \(\text{sz}\) 然后换根 DP 即可。一共 35min。

开 T3,等等这不是我图灵杯 T2 状物?考虑按照 \(\text{mex}\) 生成过程染色,那么颜色数是 \(\mathcal{O}(\log n)\),然后分讨父节点颜色和子树颜色对 \(u\) 的贡献,则可以容斥,每次固定当前点的取值做一个子集 DP 状物,这样总共是 \(\mathcal{O}(n \log^2 n)\) 的,相对好写,一共 1h40min 左右。

接下来还剩下不到半小时,写了一下 T4 的 \(\mathcal{O}(n^2)\) 暴力就跑了。

这场显示出我对类似结构的不同求解对象之间的转化还不够快也不够准,不然 T3 重推那个子集 DP 花不了那么久,另一方面显示出代码能力不足。以及就是赛后补题反映出对 T4 这种复杂数据结构题的理解还不够深入。

然后,出场就告诉我,T1 没删 freopen,直接挂 100 分,rk 15 变 rk 54,无敌了。


T1

tag:字符串、Trie。

首先可以操作这个串,如果 \(s_1 = s_n\) 那么将这两个删掉,直到无法操作为止。

考虑剩下来这个串,记为 \(T\),那么至多只能用一次操作让 \(T\) 变得完全可删去,所以本质上是要找到一个串 \(X\) 使得 \(T = X^2\),这完全等价于 Trie 树上一段折返的路径,走到底又走回原点,那么直接建 Trie 树,每个节点存父节点和所有子节点,按照上面说的遍历即可。

时间复杂度 \(\mathcal{O}(n|\Sigma|)\)。

ac link


T2

tag:换根 DP,组合计数。

首先考虑不变量或者计数顺序,注意到最后必定有一个点剩下来,考虑定这个点为根,那么一条边对应的约束大概就是未领取任务那个点指向领取任务那个点,形成一棵外向树。并且根节点的权值大于领域内任意一点的权值。

那么考虑固定根节点的时候怎么做,考虑一条边 \(u \to v\),以及 \(v\) 的子节点 \(z\)。如果 \(p_z \gt p_v\) 那么必须先操作 \(e_v\) 再操作 \(e_z\),否则先操作 \(e_z\) 的时候 \(v\) 会先领取,这个时候边的顺序就爆了。如果 \(p_z \lt p_v\) 则没有相关的限制。所以只有当 \(p_z \gt p_v\) 时需要有 \(e_v\) 先于 \(e_w\) 这一限制。这个等价于树上拓扑序,求出子树大小 \(\text{sz}(u)\),那么方案数就是 \(\frac{(n-1)!}{\prod_{v \in \text{son}(u)} \text{sz}(v)!}\) 。

再考虑对所有局部最大值的 \(r\) 做这个,实际上要维护的就是子树大小,这个可以直接换根,转移是平凡的,因为任意时刻的每一个 \(\text{sz}\) 都是 \(n\) 以内的整数,所以可以预处理逆元,时间复杂度 \(\mathcal{O}(n)\)。

ac link


T3

tag:树形 DP、状态压缩、均摊分析。

考虑把染色过程放到树上,每条边定向为先染色顶点指向后染色顶点。那么一个序列可行当且仅当相邻顶点颜色不同,且每个 \(c_u = k\) 领域内至少要有 \(0,1,2,\dots,k-1\) 这些取值。必要性显然,充分性可以直接对着树拓扑序构造,那么必定是合法的。问题变为数这个东西。

首先因为子树之间不交,所以想要凑出一个 \(k\),至少需要根节点颜色为 \(0,1,2,\dots,k-1\) 的子树,归纳做到当前颜色为 \(k\) 的子树大小至少是 \(1 + 2^0 + 2^1 + \dots + 2^{k-1} = 2^k\)。换言之颜色数是 \(\mathcal{O}(\log n)\) 的。

那么这个时候因为第二维是 \(\mathcal{O}(\log n)\),所以可以直接 DP 了,对顶点 \(u\),考虑它的贡献情况,要么是子节点包含了 \(0,1,2,\dots,c_u - 1\),要么是缺了一个颜色由父节点补上。对前者可以设 \(f(u,k)\) 表示父节点颜色大于 \(k\),且 \(c_u = k\) 的方案数。同理 \(g(u,k,x)\) 表示父节点颜色为 \(x \lt k\),且 \(u\) 的颜色为 \(k\) 的方案数。那么相应的可以直接合并到 \(g(u,k)\) 表示父节点颜色为 \(k\),且 \(u\) 的颜色不为 \(k\) 的方案数。

那么可以直接刻画出第二维的上界 \(h_u\) 表示 \(f(u,k)\) 可能非零的最大的 \(k\)。如果 \(u\) 颜色为 \(x\),父节点颜色不小于 \(x\),那么 \(0,\dots,x-1\) 必须分别由不同的子节点贡献过来,子节点 \(v\) 可以贡献颜色 \(t\) 当且仅当 \(h_v \geq t\)。所以可以对这个 \(v\) 分层计数,那么可以通过看 \(\text{cnt}_j \geq c_u - j\) 得到最大的 \(c_u\)。

再思考实际的转移,可以容斥。固定 \(u\) 的颜色为 \(c_u\),令 \(M \subseteq \{0,\dots,c_u-1\}\),对一个子节点 \(v\),钦定 \(c_v \notin M\),则方案数为 \(g(v,c_u) - \sum_{j \in M} f(v,j)\)。所以对于 \(f,g\) 的转移,"至少"对应的式子就是 \(W_{c_u}(M) = \prod_{v \in \text{son}(u)} \left(g(v,c_u) - \sum_{j \in M} f(v,j)\right)\)。那么也就有

\[f(u,c_u) = \sum_{M \subseteq \{0,\dots,c_u-1\}} (-1)^{|M|} W_{c_u}(M) \]

同样也就有

\[g(u,c_u) = \sum_{p=1}^{c_u-1} \sum_{M \subseteq \{0,\dots,c_u-1\} \setminus \{p\}} (-1)^{|M|} W_{c_u}(M) \]

但是如果直接做是 \(\mathcal{O}(n \log^3 n)\) 的,思考如何优化。因为 \(c_u \gt h_u\) 时必定有 \(f(u,c_u) = 0\),所以可以分层枚举每个 \(p\) 时加入对应的转移 \(v \in \text{son}(u), \min(h_v, c_u - 1) = p\),对当前上界 \(p\),计算出

\[T_{p}(S) = \prod_{v : \min(h_v,c_u - 1) = p} \left(g(v,c_u) - \sum_{j \in S} f(v,j)\right) \]

那么 \(W\) 就可以直接由每个 \(p\) 对应的答案连乘在一起,这样单次转移时间复杂度为 \(\mathcal{O}(c_u \times 2^{c_u} + \sum\limits_{v \in \text{son}(u)} 2^{\min(h_v,c_u - 1)})\),实际上也就是 \(\mathcal{O}(n \log n)\),故总时间复杂度就是 \(\mathcal{O}(n \log^2 n)\)。

ac link


T4

tag:单调栈、二分。

首先对每个出现的元素 \(a_i\) 求出直接前驱和后继,即左右两侧最近的位置 \(j \lt i \lt k\) 使得 \(a_j = a_i = a_k\),记为 \(p_i,s_i\)。

那么可以考虑枚举左右端点 \(l,r\),判定区间合法可以取出每个元素在该区间中最右侧出现的位置 \(q_1, q_2, \dots, q_k\),如果对所有 \(1 \leq i \leq k\) 都有 \(p_{q_i} \geq l\) 并且 \(\max\limits_{1 \leq i \leq k} p_{q_i} \lt \min\limits_{1 \leq j \leq k} q_j\) 那么必定是合法的,否则不合法。必要性显然,充分性考虑对 \(i = 1, 2, 3, \dots, k\),取出最右侧最小的使得合法的区间,即为 \([p_{q_i}, q_i]\),上面两个条件说明这些区间必定有交,那么 \(m\) 可以在交集内任取,故充分。你取出第一个位置然后找 \(s_{q_i}\) 也是等价的,两种任选一种做都没问题。预处理 \(p_i,s_i\) 之后枚举 \(r\) 和每种元素即可确认所有合法的 \(l\),因为对每一种取值分开考虑的话,\([l,r]\) 合法代表 \([l-1,r]\) 也合法,所以可以直接做到 \(\mathcal{O}(n^2)\)。

上面给到了一些有用的观察:

  • 可以拆到对每种取值考虑。最后转化回区间求交问题,那么只需要保留一些极大/极小的下标信息,会方便很多。
  • 如果一个取值是第一次出现那么贡献必定为 \(0\),由此结合上一条观察可以将整个序列划分成若干条链,每条链上元素取值完全相同。
  • 在做 \(i - 1 \to i\) 时,只有 \(m \geq p_i\) 的部分的对应贡献会产生变化。所以对一次这样的变换,只需要考虑所有 \(m \in [p_i, i - 1]\) 的区间。
  • 合理的进一步的思路是只枚举一个端点,用某些性质来统计另一个合法端点的数量。

进一步转化为,对每个 \(r\) 统计有多少个合理的 \(l\),那么根据上面说的,可以将有效的下标视为若干个段,每个段的左右端点都是严格单调的(单个元素区间严格不交),故可以直接用单调栈维护之前所说的“区间求交”对应的信息,每次新增一个数时这个数的取值对应的 \(q_i\) 会产生变化,因此我们将 \(p_{q_i}\) 对应的下标区间拿出来用新的位置对应的区间取代进去,这样可以对所有合法 \(l\) 的位置操作,因为这些位置此时也是单调的所以直接删到全部剩下合法的即可。然后又因为是单调的所以可以直接二分得到最远的可扩展位置,这样就可以确定新的区间左右端点分别在哪。

每个取值对应的区间可以直接用链表来维护,每个右端点可行的 \(l\) 可以用单调栈维护,时间复杂度 \(\mathcal{O}(n \log n)\),瓶颈在二分查找。

ac link


posted @ 2026-09-27 19:02  Twistedmind  阅读(4)  评论(0)    收藏  举报