Codeforces Good Bye 2024 部分题解
F. Earnest Matrix Complement
简要题意
给定 \(n \times m\) 的矩阵,包含 \(-1\) 或 \([1,k]\) 的整数,定义 \(c_{i,u}\) 表示第 \(i\) 行 数字 \(u\) 的个数。
要求将 \(-1\) 替换为 \([1,k]\) 的整数,最大化:
题解
引理:每一行替换的数字都一样。
考虑固定 \(i-1\) 行和 \(i+1\) 行,那这一行填一个数字的贡献是固定的,选择贡献最大的那个数字,用调整法调整一下。
考虑简单的 DP,设 \(f_{i,u}\) 表示前 \(i\) 行,第 \(i\) 行填 \(u\) 的最大贡献,这里的最大贡献指填 \(-1\) 带来的贡献,不考虑原矩阵自带的贡献。并设 \(w_i\) 为这一行 \(-1\) 的个数,于是:
我们发现当某数字在第 \(i,i-1\) 行均不存在时,\(c_{i,u},c_{i-1,u}\) 都是 \(0\),此时转移为:
此时,转移形如,先对整体做区间加法(后者),再对整体做区间取 \(max\)(前者)。
并且,两行的颜色总数量是 \(O(m)\) 的,我们可以暴力更新所有出现过的颜色的状态。以及,找到最大的 \(f_{i-1,v}+c_{i,v} \cdot w_{i-1}\) (对于出现过的颜色暴力判断,没出现过的颜色直接查询全局最大值)。
我们用线段树维护这个过程,现在看看怎么同时维护区间加,区间 \(max\) 的标记的。
用 \(max , +\) 矩阵表示这个过程:
于是我们维护一个矩阵下传的 tag 即可。事实上线段树本质在模拟线性代数,我们一直在维护一些线性映射,只是简化了矩阵乘法的过程。
再简化一下这个式子,我们发现每次都是先全局区间加,并且立刻跟上整体区间 \(max\) ,于是两个转移矩阵可以合并:
tag的合并为(设 \(g_{add},g_{max}\) 为父节点的下传 tag):
于是,标记下传便是:加法直接相加,最大值加上加法标记和父节点最大值比较取最大。而更新状态便是对 \(f_i+add\) 和 \(mx\) 取最大值。
G. Naive String Splits
简要题意
判断两个字符串 \((t_1,t_2)\) 能匹配字符串 \(s\) 当且仅当:能将 \(s\) 划分为若干个子串,每一个子串不是 \(t_1\) 就是 \(t_2\)。
给定串 \(t\) 和 \(s\) ,对于 \(t\) 的每个分割点判断 \((t_1t_2\dots t_i,t_{i+1}\dots t_m)\) 能否匹配串 \(s\)。
题解
若 \(t,s\) 有共同循环节,情况会变容易,即存在字符串 \(P\):\(t=k_1P,s=k_2P\),若分割点恰好分割在 \(P\) 末尾,原问题变为求 \(wx+(k_1-w)y=k_2\) 是否存在非负整数解。\(w\) 是 \(t_{1\dots i}\) 有几个 \(P\)。可以做扩展欧几里得,也可以暴力枚举 \(x\) ,枚举总数是 \(\sum \frac{k1}{i}\) 是调和求和。
考虑没有公共循环节的情况,我们断言,此时对 \(s\) 的划分方案是唯一的(感性理解一下)。如何得到这个方案,我们设 \(t\) 的划分为 \((t_1,t_2)\) 且 \(|t_1|<|t_2|\) ,简单的想法是不断匹配 \(t_1\) ,不能匹配再匹配 \(t_2\) ,这是错误的,比如数据 \((ab,ababc)-(abababc)\) 。
或者,不断匹配 \(t_2\) ,最后匹配 \(t_1\) ,不能通过这个数据 \((ab,aba)-(ababa)\) 。
两种情况的失败有共同点:\(t1\) 总是 \(t2\) 的前缀,贪心匹配 \(t_1\) 会导致占用 \(t_2\) 的部分前缀;贪心匹配 \(t_2\) 时当 \(t_2\)末尾有部分 \(t_1\) 的部分时,会导致 \(t_1\) 失配。
我们从贪心匹配 \(t_1\) 出发,既然占用了 \(t_2\) 的前缀那就补回去,设 \(t_2=k t_1+t\),若 \(t_1,t_2\) 均失配时,向前回撤 \(|kt_1|\) 个单位再匹配 \(t_2\) , 若还是不能配对,那可以断言这组分割是不能配对的。这里要注意的是:撤回操作时要看看之前的配对中是否至少配对了 \(k\) 个 \(t_1\) ,比如 \((a,aba)-(ababa)\) 数据,在匹配到第 \(4\) 个字符时,由于前面的 \(aba\) 是 \(t_2\) 配对的,不能撤回。
在这组策略下,每个 \(t_2\) 的配对都是不相交的,所以单组询问配对次数是 \(\frac{n}{\min(|t_1|,|t_2|)}\) ,对所有询问求和是调和求和,总复杂度 \(O(nlogn)\)。
处理配对使用哈希或 \(Z\) 函数。
I1. Affectionate Arrays (Easy Version)
简要题意
给定序列 \(a_n\) ,满足 \(\max(|a_i|)<=\sum a_i\) ,构造序列 \(b_m\) 满足:
- \(a_n\) 是 \(b_m\) 的子序列。
- \(\sum a_i=\sum b_i\) 。
- \(b_m\) 的最大子段不大于 \(a_n\) 的最大子段和。
- 满足上述要求, \(m\) 尽可能小。
求出最小的 \(m\) 。
题解
设 \(\sum a_i =s\) 。
设 \(b_m\) 的最大子段和为 \(L_b\) , 则必有 \(L_b \geq s\) (因为 \(a_i,b_i\) 和相等),那么我们可以构造出 \(L_b=s\) 。
我们将最大子段和转化为前缀和的加减问题,可以发现 \(L_b=s\) 等价于 \(b\) 的所有前缀和都在区间 \([0,s]\) 上,令前缀和为 \(P_i\) :
- 充分性:首先有 \(P_m=s\) ,若存在位置 \(k,P_k <0\) ,那么区间 \([k+1,m]\) 有更大的子段和;若存在位置 \(k,P_k >s\),则区间 \([1,k]\) 有更大子段和。
- 必要性:可以发现对于 \(i<j,P_i-P_j \leq s\) ,且 \(P_m=s\) 。
考虑 DP,设\(f_{i,j}\) 为目前考虑了 \(a_{1 \dots i}\) ,前缀和为 \(j\) 至少需要多填几个数,初始时 \(f_{0,0}=0\) ,答案为 \(f_{n,s}+n\) ,有转移:
以 \(a_i>0\) 为例,我们可以发现该转移实际上是进行一个长度为 \(a_i\) 的滑动窗口,先将 \([0,s-a_i]\) 的值依次复制到 \([a_i,s]\) 上,再对其余所有位置取全局最小值加一。
根据此观察,我们能发现 \(f_i\) 的最大值最小值差最多为 \(1\) ,且最小值的位置构成区间,我们归纳的证明这个结论:
初始时该区间为 \([0,0]\) 符合条件。假设上一次的区间为 \([l,r]\) ,对于 \(a_i>0\) ,若 \([l,r]\) 和区间 \([0,s-a_i]\) 有交集,则全局最小值不变,该区间变为 \([lc+a_i,rc+a_i]\) ,\([lc,rc]\) 为交集区间;否则没有交集,则最小值加一,区间变为 \([a_i,s]\) 。对于 \(a_i<0\) 是同理的。
于是我们维护这个区间和当前最小值即可。

浙公网安备 33010602011771号