Codeforces Good Bye 2024 部分题解

F. Earnest Matrix Complement

简要题意

给定 n×m 的矩阵,包含 1[1,k] 的整数,定义 ci,u 表示第 i 行 数字 u 的个数。

要求将 1 替换为 [1,k] 的整数,最大化:

u=1ki=1n1ci,uci+1,u

题解

引理:每一行替换的数字都一样。

考虑固定 i1 行和 i+1 行,那这一行填一个数字的贡献是固定的,选择贡献最大的那个数字,用调整法调整一下。

考虑简单的 DP,设 fi,u 表示前 i 行,第 i 行填 u 的最大贡献,这里的最大贡献指填 1 带来的贡献,不考虑原矩阵自带的贡献。并设 wi 为这一行 1 的个数,于是:

fi,u=ci1,uwi+max(fi1,v+ci,vwi1,fi1,u+ci,uwi1+wi1wi)

我们发现当某数字在第 i,i1 行均不存在时,ci,u,ci1,u 都是 0,此时转移为:

fi,u=max(fi1,v+ci,vwi1,fi1,u+wi1wi)

此时,转移形如,先对整体做区间加法(后者),再对整体做区间取 max(前者)。

并且,两行的颜色总数量是 O(m) 的,我们可以暴力更新所有出现过的颜色的状态。以及,找到最大的 fi1,v+ci,vwi1 (对于出现过的颜色暴力判断,没出现过的颜色直接查询全局最大值)。

我们用线段树维护这个过程,现在看看怎么同时维护区间加,区间 max 的标记的。

max,+ 矩阵表示这个过程:

[fi+w0]=[w0inf0][fi0]

[max(fi,w)0]=[0winf0][fi0]

于是我们维护一个矩阵下传的 tag 即可。事实上线段树本质在模拟线性代数,我们一直在维护一些线性映射,只是简化了矩阵乘法的过程。

再简化一下这个式子,我们发现每次都是先全局区间加,并且立刻跟上整体区间 max ,于是两个转移矩阵可以合并:

[w1w2inf0]=[0w2inf0][w10inf0]

tag的合并为(设 gadd,gmax 为父节点的下传 tag):

[add+gaddmax(mx+gadd,gmx)inf0]=[gaddgmxinf0][addmxinf0]

于是,标记下传便是:加法直接相加,最大值加上加法标记和父节点最大值比较取最大。而更新状态便是对 fi+addmx 取最大值。

参考代码

G. Naive String Splits

简要题意

判断两个字符串 (t1,t2) 能匹配字符串 s 当且仅当:能将 s 划分为若干个子串,每一个子串不是 t1 就是 t2

给定串 ts ,对于 t 的每个分割点判断 (t1t2ti,ti+1tm) 能否匹配串 s

题解

t,s 有共同循环节,情况会变容易,即存在字符串 Pt=k1P,s=k2P,若分割点恰好分割在 P 末尾,原问题变为求 wx+(k1w)y=k2 是否存在非负整数解。wt1i 有几个 P。可以做扩展欧几里得,也可以暴力枚举 x ,枚举总数是 k1i 是调和求和。

考虑没有公共循环节的情况,我们断言,此时对 s 的划分方案是唯一的(感性理解一下)。如何得到这个方案,我们设 t 的划分为 (t1,t2)|t1|<|t2| ,简单的想法是不断匹配 t1 ,不能匹配再匹配 t2 ,这是错误的,比如数据 (ab,ababc)(abababc)

或者,不断匹配 t2 ,最后匹配 t1 ,不能通过这个数据 (ab,aba)(ababa)

两种情况的失败有共同点:t1 总是 t2 的前缀,贪心匹配 t1 会导致占用 t2 的部分前缀;贪心匹配 t2 时当 t2末尾有部分 t1 的部分时,会导致 t1 失配。

我们从贪心匹配 t1 出发,既然占用了 t2 的前缀那就补回去,设 t2=kt1+t,若 t1,t2 均失配时,向前回撤 |kt1| 个单位再匹配 t2 , 若还是不能配对,那可以断言这组分割是不能配对的。这里要注意的是:撤回操作时要看看之前的配对中是否至少配对了 kt1 ,比如 (a,aba)(ababa) 数据,在匹配到第 4 个字符时,由于前面的 abat2 配对的,不能撤回。

在这组策略下,每个 t2 的配对都是不相交的,所以单组询问配对次数是 nmin(|t1|,|t2|) ,对所有询问求和是调和求和,总复杂度 O(nlogn)

处理配对使用哈希或 Z 函数。

参考代码

I1. Affectionate Arrays (Easy Version)

简要题意

给定序列 an ,满足 max(|ai|)<=ai ,构造序列 bm 满足:

  • anbm 的子序列。
  • ai=bi
  • bm 的最大子段不大于 an 的最大子段和。
  • 满足上述要求, m 尽可能小。

求出最小的 m

题解

ai=s

bm 的最大子段和为 Lb , 则必有 Lbs (因为 ai,bi 和相等),那么我们可以构造出 Lb=s

我们将最大子段和转化为前缀和的加减问题,可以发现 Lb=s 等价于 b 的所有前缀和都在区间 [0,s] 上,令前缀和为 Pi

  • 充分性:首先有 Pm=s ,若存在位置 k,Pk<0 ,那么区间 [k+1,m] 有更大的子段和;若存在位置 k,Pk>s,则区间 [1,k] 有更大子段和。
  • 必要性:可以发现对于 i<j,PiPjs ,且 Pm=s

考虑 DP,设fi,j 为目前考虑了 a1i ,前缀和为 j 至少需要多填几个数,初始时 f0,0=0 ,答案为 fn,s+n ,有转移:

fi,j=min0k+ais(fi1,k+[k+aij])

ai>0 为例,我们可以发现该转移实际上是进行一个长度为 ai 的滑动窗口,先将 [0,sai] 的值依次复制到 [ai,s] 上,再对其余所有位置取全局最小值加一。

根据此观察,我们能发现 fi 的最大值最小值差最多为 1 ,且最小值的位置构成区间,我们归纳的证明这个结论:

初始时该区间为 [0,0] 符合条件。假设上一次的区间为 [l,r] ,对于 ai>0 ,若 [l,r] 和区间 [0,sai] 有交集,则全局最小值不变,该区间变为 [lc+ai,rc+ai][lc,rc] 为交集区间;否则没有交集,则最小值加一,区间变为 [ai,s] 。对于 ai<0 是同理的。

于是我们维护这个区间和当前最小值即可。

参考代码

posted @   蒻蒻虫  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示