2025 暑期模拟赛题目选记

2025 暑期模拟赛题目选记

字符替换

是洛谷 P8885 的加强版。

首先考虑字符串本质不同子序列怎么求。考虑 dp。经典的 dp 是设 \(f_i\) 表示以字符 \(i\) 结尾的本质不同子序列的个数。设 \(f_s\) 表示 \(\sum f_i\),那么加入字符 \(c\) 后有 \(f_c\to f_s+1\)。那么在本题中我们只需要维护其奇偶性,于是手玩一下发现实际上在 \(\bmod 2\) 意义下相当于将 \(f_i,f_s\) 交换这样一个操作。

考虑对于全局询问。不难发现这样的 dp 状态数很小,考虑 ddp。令 \(g_{i,f_0,f_1,f_2,f_s,t}\) 表示前缀 \(i\)\(f_{0,1,2,s}\) 状态为 \(0/1\) 时,前缀 \(i\) 好的字串个数为 \(t\)。转移就是枚举字符的形式,答案是 \(\sum g_{n,?,?,?,?,t}\)

那第二维可以状态压缩,用线段树维护矩阵做。显然复杂度难以接受。注意到 \(m\) 较大,\(n\) 较小,考虑挂在猫树上分治,可以优化一部分复杂度。注意到 dp 时一部分矩阵可以用向量替代,于是直接维护向量即可。进一步的优化是将向量在每层猫树上从下往上递推处理来优化一部分复杂度。然后这题就做完了。

麒麟草

先考虑离线的操作。将 \(x\) 轴离散化,将 \(x_1+1\) 插入 \([y_1+1,y_2]\),在 \(x_2+1\) 撤销 \([y_1+1,y_2]\)。对于询问,拆成 \(\text{Q}(x_2)-\text{Q}(x_1)\) 的形式。不难发现我们维护的实际上是一个区间历史版本和。维护两个标记 \(\text{hsm,hct}\) 分别表示在该节点上方无标记时该节点的历史版本和与被覆盖的次数,询问时从上到下加入答案的贡献即可。

对于在线,无法将询问的 \(x\) 轴离散化。那么先将修改的维度离散化后可持久化,询问时拆成历史部分和当前部分两类贡献相加即可。

abstract

就是说由于值域很小,位运算操作会改变一个位上的值,因此取值的个数是 \(O(\log V)\) 级别的。于是对于所有 路径,在 \(\text{LCA}\) 处暴力 \(O(\log^2V)\) 去合并路径,用 std::map 存一下状态数即可。

草莓之歌

是洛谷 P9338。

先考虑暴力的 dp。显然我们要做的是把序列划分成 \(k\) 个区间,每个区间内部有严格偏序的方案数。那么设 \(f_{i,j}\) 表示前 \(i\) 个数划分成 \(j\) 个区间的方案数,那么有 \(f_{i,j}=\min_{k=0}^{i-1}\{{f_{k,j-1}+w(k+1,i)\}}\)。其中 \(w(i,j)=\sum_{k=i}^j\max(0,c_k-i)\),其中 \(c_k\) 表示位置 \(k\) 前方 B 的个数,对于 \(a_k=\) B\(c_k=0\)。这样做的意义是将应该在 A 后边而实际上在这个 A 前边的 B 挪到后面来。

那这个 dp 是一个划分序列的形式啊,考虑答案呈现一个凸包的形式,于是 wqs 二分将外层削成一个 \(\log\)。考虑内层如何优化复杂度。将 \(w\) 拆开,发现这个 \(\max\) 的形式很不好处理,又注意到 \(c\) 实际上是有单调性的,于是维护一个 \(p_i\) 表示第一个 \(c_{p_i}>i\) 的位置来统计贡献,做一个前缀和的优化统计。那这是一个斜率优化的形式啊!于是总的复杂度就是 \(O(n\log n)\) 的了。

终末螺旋

这种不断扩展序列的形式通常的处理方式是线段树优化建图或直接异或哈希。由于带修所以只能用异或哈希草。现考虑静态的问题怎么做。考虑到以所有异或前缀相等的最近点对作为分界点,那么抽象出来成为一个森林,且异或前缀为 \(0\) 的点对之间认为是树根,那么第一问的答案就是树的个数,第二问的答案就是每棵树里没有被除了 \(0\) 之间点对覆盖的位置乘起来。那么对于带修,一次只会改变一个位置的前缀哈希值,那么用 std::set 动态维护一下位置,略微分类讨论,用线段树支持一下区间加区间最小值个数就做完了。

世界

首先可以容易地推出状态数为 \(O(n^2)\) 的暴力 dp,用高斯消元转移可以有 \(O(n^6)\) 的暴力分。考虑优化。写出来 dp 式子之后发现其中一维的转移有严格偏序关系,因此化一下有一个简单一些的递推式子。然后你以为可以 \(O(n^2)\) 递推了?但显然不行,由于初始状态并不在边界上,因此直接按照常规转移顺序转移是错误的。但考虑到这个式子对于非边界意义下仍然是正确的,因此我们可以带出来对于最靠近边界的非边界值的系数计算,通过联立 dp 值列出方程解出这个值,最后回代系数进行计算即可。

落子无悔

先将从上到下的操作变为从下到上的操作。然后考虑每次的决策。考虑每次从下到上按照常规的方法进行树形 dp 不太现实,因此考虑从全局上考虑问题。注意到我们可以将所有的决策贡献分为两类,分别是对于父亲的贡献和兄弟之间的贡献,而对于父亲的贡献是一定的,因此我们只需要每次在全局上选出最优的点合并即可。这个贡献是一个形如 \(\frac{s_0}{s_1}\) 的形式,std::set 动态随便做一下就可以了。

穿越银匙之门

比较有意思的题。先考虑人为添加限制。具体地,先钦定一个根,这样一来我们可以找到一些形如 " \(x\)\(y\) 先操作"的限制,那是可以拓扑排序硬做的。对于无根的情形,直接钦定一个根是错误的,可能存在每个点都被操作过的情形,那么转而枚举第一次操作,这样其实也就得出了根。

绳网委托

首先反转整序列一定更优。考虑将权值分别赋为 \(0/1\),那么转化一下可以转化为选取一个权值最大的前缀。那么这个东西实际上是来自于一段前缀和一些权值和最大的子区间翻转而来。由于要进行多次操作,因此寻找的过程用线段树维护,每次将反转后的区间设为相反数来保证贪心的选取一定正确。

亲戚

考虑每次维护儿子对于父亲的贡献。对于每个点维护包含这个点的限制,那么可以合并的条件是父亲包含了所有儿子的限制。然后这个东西用 std::bitset 维护,加入一些优化保证复杂度即可,反正也跑不满。

花之舞

考虑采用平面最近点对期望 \(O(n)\) 的网格图维护方式。先考虑不删的情形,我们将平面按照 \(2^0,2^1,\cdots,2^d\) 长度划分为网格图并加入 \(O(1)\) 个点的贡献,扫描线加入一下贡献,这个可以用常数小的分块做,对于删除的情形,多维护一下删除后距离最小值之类的东西分讨统计贡献即可。

posted @ 2025-08-16 21:41  长安19路  阅读(8)  评论(0)    收藏  举报