26DMYCSP-S#7
Daimayuan CSP-S 2026 Round 7
闲话
这场有点太猎奇了。
25min 看完四个题,T1 像是 typical 的差分处理后分析环上的等价类,T2 像是考虑一些周期/border理论的计数,T3 神秘随机性质题,T4 是树拓扑序计数,但看不懂它那个连续段长度不超过 \(k\) 是啥。
开 T1,注意到可以直接差分得到 \(d_i - d_{i - k} = a_i - a_{i - 1}\),取出 \(g = \gcd(n,k)\) 那么所有 \(i \bmod g\) 相同的位置属于一个等价类,每个等价类内单独贪心即可做到线性。20min 左右。
开 T2,首先肯定是一段周期加一段不能被拆为任意周期的东西。如果仅考虑前一段直接可以 \(\mathcal{O}(1)\),考虑后一段那么问题变为每次可以选取整周期的若干次幂 \(T,T^2,\dots,T^{k-1}\) 或者后一段串的一段。那么可以给每个串固定其表示为操作次数最少的操作序列。因为可行的操作是一个区间,这样可以直接求出区间的左端点,用 \(\sum_{i} (y + 1)^i\) 状物可以确定区间右端点,则可以直接一次容斥解决。大概 1h 左右。
开 T3,首先可以确定连边是max-笛卡尔树状物,因此可以直接利用笛卡尔树的连边来刻画支配对,因此可以用类似于无旋 Treap 的结构来维护 \(\text{swap}(p_i,p_j)\),又因为数据随机所以 Treap 的非退化性质是可以保证的。大概 1.5h 左右。
然后开始坐牢,T4 会不了一点,打了个指数级的部分分之后想了一万年正解,最后只会 \(\mathcal{O}(n^2k)\) 或者多项式优化到 \(\mathcal{O}(n^2 \log^2 n + nk)\),这两个都巨难写会不了一点,红温了。
最后没有挂分,10 个大样例还是太权威了,\(100+100+100+15=315\),rk 2。
赛后花一天的时间补了 T4,这个确实是好题,很多容斥结构本身也可以是不平凡的东西,只要你能确定它和原计数对象构成双射,且这个结构自己有明确的容斥系数即可。容斥这个技术被应用在某个计数对象上就是因为该计数对象难以直接被刻画,而只能用部分性质来框定它包含或包含于一些好刻画的对象。类似的题还有AGC058D和QOJ13456,学到了。
T1
tag:贪心,数论。
首先区间操作肯定想到差分,令 \(d\) 为差分序列那么 \(d_i - d_{(i - k) \bmod n} = a_i - a_{(i-1) \bmod n}\),由此我们可以将整个大环分成 \(m=\gcd(n,k)\) 个等价类,对每个 \(r \in [0,m-1]\),我们知道所有 \(r + t \times m, 0 \leq t \leq \lfloor \frac{n - r}{m}\rfloor\) 都在一个等价类中。
因为同一个等价类内,任意两个相邻元素之间的差值由差分决定,所以可以对每个环取出其中最小的数使得这个数变为 \(0\),此时环上所有数都确定了。由此问题转化为对每个环定一个基准值 \(\Delta_c\),每个环上的数此时变为 \(d'_i = d_i - \Delta_c\),使得全局为 \(0\)。
令 \(S_i = \sum_{t=0}^{k-1} d_{(i - t) \bmod n}\),则由差分序列约束可知 \(S_i - S_{i-1} = a_i - a_{i-1}\)。也即所有 \(S_i - a_i\) 是相同的。因此题目条件等价于 \(\sum_{j=0}^{n-1}S_j = \sum_{j=0}^{n-1} a_j\),也即 \(k \times \sum_{i=0}^{n-1} d_i = \sum_{j=0}^{n-1} a_j\)。拆到每个环上就是 \(k \times \sum_{i=0}^{n-1} d'_i + k \times \frac{n}{g} \sum_{j=0}^{g-1} \Delta_{j} = \sum_{i=0}^{n-1} a_i\)。由此所有环的基准值之和 \(\sum_{i=0}^{g-1} \Delta_{i} = \frac{\frac{1}{k} \sum_{j=0}^{n-1} a_j - \sum_{i=0}^{n-1} d'_i}{n/g}\) 即可确保全局的等量关系成立。
由此每个环找的基准值必定为 \(-\min\limits_{i \equiv r \pmod g} d'_i\),贪心地把所有非零的量转移到基准值最小的环上即可。时间复杂度 \(\mathcal{O}(n)\)。
T2
tag:border结论,组合数学,容斥原理,Ad-hoc。
滚木来咯!
设当前询问的串长为 \(m\),所有周期从小到大为 \(p_1, \dots, p_t\),那么因为每次操作后 \(U\) 均以 \(S\) 结尾所以合法的追加长度恰好是 \(S\) 的所有周期长度(包括 \(m\))。
令 \(x = \lfloor m / p \rfloor, y = t - x\),如果一个周期 \(p_i\) 不是 \(p_1\) 的倍数,则一定有 \(p_i \gt m - p\),否则因为 \(\gcd(p_1,p_i)\) 也是周期就与 \(p_1\) 为最小周期矛盾了。因此长度为 \(|p_1|,2|p_1|,\dots,t \times |p_1|\) 的追加串分别是同一个串 \(p_1\) 的 \(1, 2, 3, \dots, t\) 次幂。其余 \(y\) 个可行的周期均不能拆为两个合法周期之和,记为 \(T_1,T_2, \dots, T_y\)。
则由 \(p_1^{u}, T_1, T_2, \dots, T_y\) 中若干个串拼接而成的串必定是唯一的,因为追加一个 \(T_i\) 的时候不可能在前后两次 \(S\) 的出现位置之间还出现一次,否则该周期即可拆成两个合法周期,与 \(T\) 的意义矛盾了。所以最终字符串 \(S\) 中的全部出现位置恰好恢复成上面拼接结果。因此问题变为,用恰好 \(k - 1\) 个上面的块,能组成多少种不同的 \(U\)。
因为每将一个 \(p_1^{u}\) 拆成 \(p_1^{v}, p_1^{u - v}\) 时本质上都是做加法意义的拆分,所以一个串对应的块数必定是一个区间。对于一个含有 \(i\) 个 \(T\) 中的串,每个连续 \(p_1\) 段长度为 \(l_0,l_1,\dots,l_i\) 的串,对应的可能块数恰好对应区间 \(\left[i + \sum_{j=0}^{i} \left\lceil \frac{l_j}{x} \right\rceil, i + \sum_{j=0}^{i} l_j \right]\)。
那么此时问题就很清晰了,用所有左边界 \(\leq k - 1\) 的串数,减去所有右边界 \(\lt k - 1\) 的串数,即为所求。
对于左边界的限制,我们考虑将一个 \(U\) 与最少操作次数对应的操作序列对应起来,这个显然双射,因此对连续的一段 \(p_1^{q}\) 必定是先尽可能分出若干 \(p_1^{t}\),然后最后剩下一段 \(p_1^{q \bmod t}\)。如果一个 \(U\) 的末尾恰好没有 \(q \bmod t\) 对应的串,那么因为每个散块后面必然紧接一个 \(T_i\),二者合并就只剩下两类转移,一类是单个的 \(p_1^{t}\) 或 \(T_i\),对应 \(y + 1\) 种选择,另一类是 \(p_1^{u} T_j, 1 \leq u \lt t\),对应 \(2\) 个块的长度以及 \(y(x - 1)\) 种选择,所以有转移 \(f_i = (y + 1)f_{i - 1} + y(x - 1)f_{i - 2}\)。则所求即为 \(\frac{f_{k + 1} - 1}{b}\),另一侧对应的恰为最少操作次数不超过 \(k - 1\) 的串中,无法恰好使用 \(k - 1\) 次操作的串的数量,也即 \(\sum_{j=0}^{k-2} (y+1)^i\)。故答案即为二者做差 \(\frac{f_{k+1}-1}{b} - \sum_{j=0}^{k-2} (y+1)^i\)。这个 \(f\) 的递推可以直接矩阵快速幂/倍增处理,故时间复杂度 \(\mathcal{O}(n + q \log k)\)。
T3
tag:笛卡尔树,均摊分析,Treap,Ad-hoc。
这个真吓死我了。
考虑对 \(p\) 建立大根笛卡尔树,因为 \(p\) 是排列,所以将位置作为key,\(p_i\) 作为优先级,那么这也是一棵 Treap。
考虑一棵子树对应的区间 \([l,r]\),假设根节点在 \(u\),那么题目的连边条件等价于 \([l,u-1]\) 中所有点向 \(u\) 有连边,\([u+1,r]\) 中所有点向 \(u\) 连边,同时 \([l,u-1],[u+1,r]\) 之间没有连边。换言之题目中的连边关系就等价于笛卡尔树上的祖先关系。
考虑直接维护笛卡尔树上每棵子树对应的区间信息,每个区间维护四个值 \((a,b,c,d)\),分别对应从区间左端点到右端点的路径数,从区间左端点到区间内任意顶点 \(x \gt l\) 的路径数,对称地从顶点 \(x \lt r\) 到 \(r\) 的路径数以及所有 \(l \leq x \leq y \leq r\) 对应的 \((x,y)\) 路径数。
这样就可以直接合并每个区间了,如果新的最大值在右侧那么每个点可以向这个端点连边,有 \((a,b,c,d) \to (b, 2b, 1 + d, 1 + 2d)\),同理如果在左侧那么 \((a,b,c,d) \to (c,1 + d, 2c, 1 + 2d)\)。合并两个区间 \((a_1,b_1,c_1,d_1),(a_2,b_2,c_2,d_2)\) 时,设左区间的右端点等于右区间的左端点,为全局最大值,那么任意从左侧跨到右侧的边必须经过中间点,有新区间信息
那么每次合并左右子树就可以直接先拿两个子区间和中间的 \(u\) 合并,再将两个整区间合并。所以我们可以直接类似于 fhq-Treap 的思路维护整棵树,每次交换操作将 \([1,i-1], i, [i + 1, j - 1], j, [j + 1, n]\) 分别分裂出来,交换 \(p_i,p_j\) 后合并回整棵树即可。
因为排列数据随机,且每次操作后排列仍随机,所以期望笛卡尔树高度 \(\mathcal{O}(\log n)\),故时间复杂度 \(\mathcal{O}((n + q) \log n)\)。
T4
tag:树形DP,状态优化,容斥原理。
题目描述的连续段等价于树上的一条祖先-后代链,所以可以直接把问题转化为计算树的拓扑序,并确保每种被计入的拓扑序内均不存在长度大于 \(k\) 的链。
考虑容斥,那么首先需要设计每条链对应的贡献,因为我们要确保在做增量法的同时,长度严格大于 \(k\) 的所有链都只被计数一次,不能存在某条链每增加 \(1\) 的长度都被计入一次,所以考虑类似差分的思路来设置系数。如果长度 \(t = k + 1\) 那么系数 \(c_t = 1\),如果 \(t = k + 2\) 那么系数 \(c_t = -1\),其余情况有 \(c_t = 0\)。
考虑对一段长度为 \(t\) 的极长的链,将其任意拆分为若干非空连续链,并对这些连续链的系数做乘积,对所有拆分方案求和,记该权值和为 \(w_t\),则有 \(w_t = \sum_{i = 1}^{t} c_i \times w_{t - i}\)。生成函数化简得到 \(w_t = [t \leq k]\)。那么对一个已经固定的顺序 \(a\),将每一段极大的链任意切分后求系数对应的权值和,如果所有分段长度均不超过 \(k\) 则有权值恰为 \(1\),否则为 \(0\),和我们需要计数的问题重合了。故原问题可以转化为枚举树上所有可能的链划分,求权值之和。
则问题可以转化为某种剖分结构意义下的树DP,每个点至多保留与一个子节点相连的边构成一条链,因此可以考虑枚举保留哪条边然后直接合并其余子树对应的方案数。将每条链缩成一个点,设剩下的树的大小为 \(m\) 则此时方案数即为 \(\frac{m!}{\prod_{i=1}^{n} \text{sz}(i)!}\),因此可以直接 DP 记录链剖分的结构以及对应的子树大小的倒数。
对每个节点 \(u\),设 \(f_u(r,b)\) 表示对 \(u\) 为根的子树进行链剖分之后,缩点后共有 \(b\) 个点,包含 \(u\) 的链模 \(k + 1\) 余数为 \(r\),不计包含 \(u\) 的块的权值对应 \(c_l\),不计包含 \(u\) 的块对应的子树大小倒数,其余所有点的权值和子树大小倒数贡献。设 \(g_u(b) = \sum_{r=0}^{k} c_r \times \frac{f_u(r,b)}{b} = \frac{f_u(1,b) - f_u(0,b)}{b}\),则 \(g\) 对应完整处理 \(u\) 为根子树后,块数为 \(b\) 的权值和。
那么可以对每个点 \(u\) 维护 \(A_u(i)\) 表示已经处理的前 \(i\) 棵子树中,没有任意一个子节点与 \(u\) 有连边的情况,以及 \(B_u(r,i)\) 对应已经处理的前 \(i\) 棵子树中恰有一棵子树与 \(u\) 连接,当前链对应模 \(k+1\) 余数为 \(r\) 的情况。处理 \(A_u(i)\) 等价于直接乘法原理合并子树答案,有转移 \(A_u(i) \times g_v(j) \to A_u(i + j)\)。同理对 \(B\) 只需要分讨当前子节点是否接到 \(u\):
- 如果不接:\(B_u(r, i) \times g_v(j) \to B_u(r,i + j)\)。
- 如果接,则需要考虑这条链对 \(u\) 所处的链的长度的影响:\(f_v(s,j) \times A_u(i) \to B_u((s + 1) \bmod (k + 1), i + j - 1)\)。
求出 \(A_u,B_u\) 后 \(f\) 对应转移即为 \(A_u(b) \to f_u(1,b), B_u(r, b) \to f_u(r,b)\);\(g\) 对应转移即为 \(g_u(b) = (f_u(1, b) - f_u(0,b)) \times b^{-1}\)。最终答案即为 \(\sum_{b=1}^{n} b! \times g_1(b)\)。直接用树上背包模拟上述转移是 \(\mathcal{O}(n^2k)\) 的。
然后有一个观察,令 \(m = k + 1\),设原始节点数 \(s\),在 \(f_u(r, b)\) 中,根节点对应链之外的 \(b - 1\) 条链都已经乘过了 \(c_l\),因此只有两类链有贡献:
- 长度模 \(m\) 为 \(1\),贡献是 \(+1\);
- 长度模 \(m\) 为 \(0\),贡献是 \(-1\)。
如果其中有 \(j\) 条负权链,则有 \(s \equiv r + (b - 1 - j) \equiv {(k + 1)}\)。因此只要固定原始节点数 \(s\) 和块数 \(b\),只需要枚举 \(j = 0, 1, 2, \dots, \min\left(b - 1, \lfloor \frac{s - 1}{k + 1} \rfloor\right)\)。所以枚举下界可以做到 \(\min\left(k, \left\lfloor \frac{n}{k}\right\rfloor\right) = \mathcal{O}\left(\sqrt{n}\right)\),总时间复杂度 \(\mathcal{O}\left(n^{2.5}\right)\)
一个很隐蔽的坑是内存问题,需要动态开 \(g,b\) 对应的 DP 数组,这样才能确保空间是严格的 \(\mathcal{O}\left(n^{1.5}\right)\) 以及包括 std::vector.assign 在内的时间是严格的 \(\mathcal{O}\left(n^{2.5}\right)\),略微卡常,需要注意两维的遍历顺序从而提高内存连续性以减小常数。
浙公网安备 33010602011771号