模拟赛选题
zzy 的金牌
可重集一类的东西是没有顺序之分的,发现 \(K\) 只有 \(300\),所以如果把最终的集合和开始的集合做差,得到一个 \(b\) 数组应该是满足 \(\forall b_i+a_i\ge b_{i-1}+a_{i-1}\) 且 \(\sum b_i=K\) 的。那么我们现在只需 DP 找出 \(b_i\) 的方案数。考虑设 \(f_{i,j,k}\) 表示考虑到第 \(i\) 个数,\(b_i\) 填 \(j\),当前的 \(\sum b_i\) 为 \(k\) 的方案数,转移是显然的。
然后变形一下,发现这个 DP 形式可以差分优化,复杂度就从 \(O(nk^3)\) 变成了 \(O(nk^2)\),可以通过。
口粮输送
赛时不应该去暴力贪心,因为这玩意一看不可贪。考虑到对于一棵树,我们从下往上让所有儿子空余的口粮汇集到父亲,然后根据父亲的口粮剩余情况再层层向上转移,最后只需检查根节点的 DP 值是否非负即可。那么对于一个图而言是同理的,最后走的一定是能够形成最小生成森林的边,那么我们只需找到这个最小生成森林,转移即可。
作弊
原:P7503。
暴力 DP 应该是极其容易的,只需暴力枚举分段即可。
这个 DP 方程很难优化,于是考虑计算每个点的贡献。以每个点 \(i\) 为中心,用树状数组可维护出向左第一个大于等于 \(l_i\) 的位置、第一个大于 \(r_i\) 的位置、向右第一个大于等于 \(l_i\) 的位置、第一个大于 \(r_i\) 的位置。分别记为 \(L_1,R_1,L_2,R_2\)。然后枚举右端点,当右端点位于 \([i,L_2)\) 时,在 \([R_1,L_1]\) 区间统计贡献;当右端点位于 \([L_2,R_2]\) 时,在 \([R_1,j]\) 区间统计贡献。线段树维护全局最大值。
牛仔
原:ARC100D。
不得不说这道题出在考场上的杀伤力巨大,但可以从一些特殊性质入手。\(k>n\) 答案一定是 \(0\),且若 \(A\) 本身就是牛仔序列,那么每一种匹配都是合法的,所以答案为 \((n-m+1)k^{n-m}\)。
考虑到题目中的这个限制比较难以正面处理,所以用总的匹配数减去不合法的匹配数,也就是当这个序列并不是一个牛仔序列时产生的匹配数,等价于这个序列中不存在长度为 \(k\) 的极长不同色连续段。
如果 \(A\) 中有相同元素,我们只关心最左边和最右边的极长不同色连续段大小 \(l,r\),然后 DP,设 \(f_{i,j}\) 表示填了 \(j\) 个元素,当前的极长不同色连续段前缀大小为 \(j\);\(g_{i,j}\) 表示同样条件下的后缀,转移分类讨论插入了和前 \(j\) 个元素同色还是不同色的元素,为
\(g\) 的转移是完全相同的。然后用后缀和优化可以做到 \(O(nk)\) 转移,然后合并时枚举左右两侧分别加入多少个元素。
如果 \(A\) 中没有相同元素,那么一定有 \(m<k\),我们就不关心具体的颜色,因为有引理可得出原序列由不同元素组成长度超过 \(m\) 的段的个数再除以 \(\mathrm A_m^k\) 就是答案,所以只统计原序列中长度为 \(m\) 的不同色子区间个数之和,转移相同,额外地,在 \(j\ge m\) 时 \(g_{i,j}\to f_{i,j}\) 即可。
数数
先考虑如何正着去做,那就是从小到大依次加数,设加入一个数之前的最大连续段长度为 \(L\),那么我们就给 \(F(1),F(2),\dots,F(L)\) 对这个数取 \(\max\) 即可。
那么反过来,如果先给定了 \(F\) 数组,那么相当于指定了加入一部分数之后,最大连续段长度恰好为 \(L\)。考虑通过这个限制进行 DP 转移,那么我们先处理出 \(F\) 数组中的每一个数出现的区间,设其为 \(l_{F(i)}\) 和 \(r_{F(i)}\),然后依然从小到大加数,存储当前的所有连续段,这一点用 \(\tt map\) 套 \(\tt vector\) 即可维护。考虑到如果当前我们要加入的数 \(x\) 在 \(F\) 中出现过,那么此时最大连续段长度一定恰好为 \(r_x\),并且加入它后的最大连续段长度一定恰好为 \(l_x-1\)。反之,如果它没有在 \(F\) 中出现过,那么我们需要保证当前加入的这个连续段不是唯一最长的,转移与上面相同。用这两个条件限制转移即可。转移可以用 \(\tt queue\) 实现。
穿越银匙之门
原:AGC027F。
判断树同构是困难的,考虑如果我们确定一个根,那么判断两棵树同构就只需判断每个节点的父亲即可,判断一个点是否需要操作也只需判断它在两棵树中的父亲是否相同即可。
然后,我们可以从中得到一些约束:
-
若 \(u\) 不需要操作,则 \(\text{fa}_A(u)\) 也不需要操作;
-
若 \(u\) 需要操作,则它必须在 \(\text{fa}_A(u)\) 前操作,在 \(\text{fa}_B(u)\) 后操作。
前者是容易判断的,后者可以建图然后用拓扑排序判断是否是 DAG。
那么现在的问题是如何确定一个根。我们自然是希望找到一个不需要操作的根,但因为有可能所有节点都需要操作,那我们就暴力枚举第一次操作,固定下来一个节点然后以这个节点为根。因为 \(n\) 很小,所以复杂度不成问题。
绳网委托
以 LIS 指代最长不降子序列,考虑转化这个求 LIS 的过程。不难发现,因为我们的序列只有 \(0,1\),所以一个 LIS 必然是由一截子 \(0\) 和一截子 \(1\) 构成。那么,你难道就不更远一点想到,如果我们把序列中每一段的 \(0\) 标记为正数,每一段的 \(1\) 标记为负数,然后找到一段 \(0\) 和一段 \(1\) 的分界点 \(p\)(\(p\) 在 \(0\) 的最后),于是这个 LIS 长度可以转化为 \(\mathit{cnt}+s_p\),其中 \(\mathit{cnt}\) 是 \(1\) 的个数,\(s\) 是刚刚我们标记了正负数的数组的前缀和。
\(\mathit{cnt}\) 是好求的,我们只需找到执行了翻转操作若干次后 \(s_p\) 的最大值。
又注意到,翻转的这些个区间必定是不交的。问题转化为选取一段前缀 和 选取若干段区间,找到它们的最大权值和。
我们可以反悔贪心。具体而言,我们每次去贪心地找最长前缀 和 最大子段和,能保证在当前操作步数下最优。每次操作完,给它们整体乘上 \(-1\),表示以后如果再一次找到了这些区间就可以撤销它们的贡献。不难用线段树维护上述操作,可以看作《山海经》加强版,需要维护区间最大子段和、最小子段和。
落子无悔
如果从上往下贪心,题解告诉我们应该将比较函数定义为 \(\dfrac{p_i}{q_i}>\dfrac{p_j}{q_j}\),其中 \(p_i,q_i\) 分别为 \(i\) 子树中 \(0\) 和 \(1\) 的数量。但是很遗憾,这是痿的,因为取走一个点以后会带来不止一个新的贡献,这些贡献可能使得这个点不再是当前最优。
考虑一个经典的 trick,变成从下往上贪心,依然按照上面的规则比较,每找到一个节点就把它和它父亲合并起来,统计答案。然后这样做就是对的。可以用一个 \(\tt set\) 实现。
体测
先考虑两种部分分。
一种是 \(a_i=1\),首先假设所有区间的右端点不重合,那么对于每个区间只需取到右端点即可满足要求。那么若存在重合的右端点,解决办法也很简单,只需把多余的右端点向左移动,直到所有右端点都不重合即可。移动的过程中需要注意:优先移动左端点更靠左的区间的右端点,以及如果出现右端点小于左端点就直接判断 Sorry。用优先队列实现。
另外一种是 \(a_i\) 互不相同,不难发现此时就是个最小点覆盖,参考 CSP-S 2024 T2。
正解其实就是结合了两种思路。首先对于每一种颜色,跑第一种部分分,其中如果有 Sorry 直接结束,否则就是正常地将每一种颜色的右端点都调整到了互不相同。此时一定有解,我们的目的是用尽可能少的点覆盖所有区间。参考第二种部分分的思路,一定存在一种最优解使得所有的点都取在右端点上,那么我们从左到右枚举所有右端点,提取出包含这个点的所有区间。因为同种颜色的活动一天只能举办一次,所以这个点顶多能覆盖每种颜色的区间各一个。贪心地,我们肯定覆盖右端点最靠左的那一个。然后给这个区间标记为已删除,已删除的区间直接跳过即可。
二分图最大权匹配
原:AGC034D。
此题为 trick 题。第一步,考虑将曼哈顿距离转化为切比雪夫距离,转化方法在此不作赘述。这样我们求的是两个绝对值的最大值,进而拆成四个值的最大值。写一下式子:
考虑费用流。具体地,将四种情况看作四种颜色,将黑点向颜色点连边,颜色点向白点连边,再建立超源超汇连接黑点和白点,跑最大费用最大流即可。
这样做能过原题,在模拟赛题上有 80pts 的高分。发现这个图没有正环,也就是说一次增广必定不会重复经过同一个颜色点。进一步总结出一次增广的流程为:从某一黑点出发找到某一颜色点,然后绕来绕去最终绕到另外某一颜色点,然后从这一颜色点出发找到某一白点。
模拟费用流。可以用堆来维护第一和第三部分的贡献,第二部分的贡献可以用 Floyd 跑最长路求出。实现比较困难,中间用到了多次懒惰删除,即在使用时才删除不符合要求的点。
灯笼
原:P9312 [EGOI 2021] Lanterns / 灯笼。
考虑 DP。设 \(f_{l,r,i}\) 表示当前能到达的海拔区间为 \([l,r]\),当前位置为 \(i\) 的最小花费。转移困难,因为有可能有很多段不相交的山峰的区间,才需要一个 \(i\) 来记录位于哪个区间。于是改为设 \(f_{u,v}\) 表示设当前区间左右端点为 \(a_u\) 和 \(b_v\),不难发现此时的山峰区间就是唯一的。转移时取一个有交的区间进行转移即可。
但此时转移是 \(O(k^2n)\) 的。优化,将 \(u\) 按 \(a_u\) 从小到大枚举,\(v\) 按 \(b_v\) 从大到小枚举。此时如果一个决策点无法转移 \(f_{u,v}\),它也必定无法转移更靠后的 \(f_{u',v'}\)。所以用优先队列维护即可,如果转移堆顶不成就直接 pop 即可。
草莓之歌
原:P9338 [JOIST 2023] 合唱 / Chorus。
首先需要了解 WSQ 二分。这个东西可以在答案关于分段数呈现出凸完全单调性时,解决给定分段数的分段 DP。然后来观察这道题,会发现一个小性质,那就是第 \(i\) 个 \(\tt A\) 与第 \(i\) 个 \(\tt B\) 必定是匹配在一起的。进而考虑一个价值函数 \(w(l,r)\),表示如果将 \([l,r]\) 这个区间的 \(\tt A\) 分为一段所产生的交换次数。不难发现,这个价值为
其中 \(c_i\) 是第 \(i\) 个 \(\tt A\) 前面的 \(\tt B\) 的个数。这个方程的意思也很好理解,就是要统计会和 \(\tt A\) 交换的 \(\tt B\) 的个数。
离能斜率优化的式子已经很近了,考虑去掉 \(\max\)。发现这个 \(c_i\) 是单调不降的,那就很显然,可以用 lower_bound 快速找到第一个 \(k\) 使得 \(c_k-i\ge0\),记为 \(p_i\)。则这个价值函数就变为了
转移方程就是
再设 \(s_i\) 为 \(c_i\) 的前缀和,直接套斜率优化的式子,最终推出
显然 \(i\) 满足单调性,单调队列维护即可。
愤怒的小 L
原:P7468 [NOI Online 2021 提高组] 愤怒的小 N。
首先需要知道这个无穷字符串是怎么构造的,并尝试找到它的通项函数。经过观察,有 \(s_n=1-s_{n-2^m}\),其中 \(m\) 为 \(n\) 的二进制下的最高位。不难发现,\(s_n\) 的取值是由 \(n\) 的二进制位下 \(1\) 的奇偶性确定的。于是得出重要的通项公式:
下文中 \(\operatorname{popcount}(i)\) 简记为 \(\text{P}(i)\)。再用一个公式化掉 \(\bmod2\):
而我们要求的是 \(\sum_{i=0}^{n-1}s_if(i)\)。将刚才求出的 \(s_i\) 的通项公式代入,得
前半部分,我们知道一个 \(k-1\) 次多项式做前缀和后会得到一个 \(k\) 次多项式,即前半部分是一个新的多项式 \(F(i)=\Sigma f(i)\),拉格朗日插值即可求出。
后半部分,并不是很好处理。考虑把 \(f(i)\) 拆开得到
这时考虑将 \(n\) 按 \(\tt lowbit\) 拆开,拆成若干区间,比如 \((1101)_2\) 就会拆成 \([0000,1000),[1000,1100),[1100,1101)\) 这么几个区间。记 \(u\) 为区间左端点,\(t\) 为 \(\log_2(\text{区间长度})\),原式变为
进一步,
此时,注意到一个小性质,那就是 \(u\) 在二进制下的最低位一定高于 \(t\) 在二进制下的最高位,证明显然。那就能得出 \(i\) 在二进制下的最高位也一定低于 \(u\) 在二进制下的最低位。于是说明 \(i+u\) 在二进制下不会产生进位,于是有 \(\text{P}(i+u)=\text{P}(i)+\text{P}(u)\)。于是将 \(\text{P}(i+u)\) 拆开,后面的 \((i+u)^r\) 用二项式定理展开,整理得
发现式子的最后变成了前文某式的子问题:若记
则现在就能得出
考虑计算 \(S(0,t,j)\)。注意到这个式子对于 \(S(0,t,j)\) 其实是不适用的。只能扰动法,最终求出
对于 \(S(2^{t-1},t-1,j)\),可以继续展开。边界条件显然为 \(S(0,0,j)=[j=0]\)。
此时直接算还是不行。但是注意到,当 \(t>j\) 时,\(S(0,t,j)\) 恒等于 \(0\)。于是状态数就减少到了 \(k^3\) 个,就可以直接算了。
对取模后的数进行位运算是愚蠢的。
银行的源起(banking)
考虑只有一个银行的情况,实际上就是树的带权重心。套路地,将贡献拆成每条边的贡献,不难发现答案就是 \(\sum w\times\min(\text{siz}(u),\text{siz}(1)-\text{siz}(u))\)。
现在考虑两个银行。需要发现的是,此时一定存在一条边是没有人走的。考虑枚举这条没有人走的边,则原树断为两棵树,化为两个子问题,采用上文的方法即可。
此时复杂度 \(O(n^2)\)。枚举断边的思路是正确的,考虑优化统计答案的过程。
\(\min\) 很不好处理,于是拆开,每条边 \((u,v)\) 的贡献就化为
其中 \(X\) 就是总的 \(\text{siz}\)。不难发现,此时一棵子树的贡献相当于询问一段 dfn 区间内小于等于某个值的数的贡献和,直接主席树维护 \(w\) 和 \(w\text{siz}(v)\) 即可完成。那么其中一棵子树的答案就完成了,考虑如何计算另一棵子树。发现此时答案受影响的只有 \(1\) 到 \(u\) 这条链上的点,受到的影响就是它们的 \(\text{siz}\) 全部减去了 \(\text{siz}(v)\)。也就是此时的查询变为 \(\text{siz}(i)-\text{siz}(v)\le X/2\)。移项就能避免链减。至于剩下的部分,可以先用主席树查,然后再开一棵线段树维护链,把错误计算的链的部分减去,再加上正确的链的部分,就是答案。
道路修建
加入一条边后,原树变为一棵基环树,环上每个点都对应一棵子树。依然是考虑每条边的贡献:
-
环边:任意不在同一子树内的两点都会经过环边,答案为 \(\dbinom n2-\sum_v\dbinom{\text{siz}(v)}2\);
-
环上其他边:任意不在同一子树内的两点都会经过环上其他边,但没加边前有一遍已经算过了,所以减去:\(\dbinom n2-\sum_v\left(\dbinom{\text{siz}(v)}2+g_v\right)\),其中 \(g_v=\text{siz}(v)\times(n-\text{siz}(v))\);
-
树边:计算总贡献,即从子树内走向子树外,记 \(f_i=\sum_{v\in i}\text{dis}(i,v)\),一棵子树的贡献就是 \(f_i(n-\text{siz}(i))\)。
所以总贡献为
由三部分组成。考虑树剖,每个节点只维护轻儿子的贡献,这样除了 LCA 和链底,剩下的部分都可以直接求了。特殊处理这三个部分,即可。说得云淡风轻,写起来很史。
生命之树
看着很典,积累一下套路。
注意到,一个子树中的点只能和子树外的至多一个点匹配。感性理解。因为数据范围是 \(n^2\) 的,所以直接设 \(f(u,j)\) 表示子树 \(u\) 中,和 \(u\) 匹配的点是 \(j\) 的答案。再设 \(g(u)\) 表示合法的 \(f(u,j)\) 的最小值。这个 \(j\) 实际上并不需要必须在子树外,\(j\) 合法当且仅当 \(\operatorname{dis}(u,j)\le d_u\)。
然后就可以开始 DP 了。对于 \(u\) 的一棵子树 \(v\),有且仅有两种情况:
- \(v\) 子树的所有点全在 \(v\) 子树内匹配,此时 \(v\) 的贡献就是 \(g(v)\);
- \(v\) 子树的点和 \(j\) 匹配,那么提供的贡献就是 \(f(v,j)-c_j\),因为 \(j\) 的贡献我们在 \(u\) 已经算过了。
综上,总的转移方程就是
最终答案为 \(g(1)\)。
染色
其实是比较靠前的一道题,偶然想起就补一下。
这题看着似乎能用树剖等树上数据结构切掉,但你会发现在线区间数颜色暴力维护直接变成 \(O(n^2)\)。仔细想想这玩意常规手段搞不了。发现暴力做的修改 \(O(1)\),查询 \(O(n)\)。所以正解应该是个均摊复杂度,比如定期重构这种。
答案是 bitset。如果我们能把路径上的 bitset 全部或起来,问题自然解决了。但这样做似乎时空都难以承受,至少在时间方面,直接提取出一条路径需要树剖,前面已经讨论过了,不行。于是考虑刻画树上路径的另一种方法,即 LCA。发现我们只需要求出每种颜色是否在路径上只出现一次。考虑改为求 bitset 的异或。这样如果维护从根到 \(u\) 的 bitset,只需用 \(u\) 的 bitset 异或 \(v\) 的 bitset,LCA 及以上的部分就会抵消,路径就刻画出来了。
(未完)

浙公网安备 33010602011771号