CF1383E:Strange Operation题解
CF1383E
题意:输入01串,有如下操作:相邻的 10,01,11 变成 1,或者 00 变成 0,求若干次操作后得到的本质不同的新 01 串数量。
Solution:
两个数变成一个数,可以视作删掉一个数。
如果是可以删除任意数字若干次,那就是子序列自动机上的dp,说白了就是 。
但显然这题里删除 1 的条件比删除 0 要苛刻,对于一个 1 两侧的 0,想要让它们汇合就必须删掉中间的 1,而删掉中间的 1 则需要删除任意一侧全部的 0。
我们把相邻两个 1 中间的 0 的数量提取出来,形成一个新序列 a(首尾 0 的个数也算进来),相邻两个数都是 1,那么 a 的这一项就是 0。每一个 a 序列对应一个 01 串,输入的 01 串以及我们求的各个本质不同 01 子串都是如此。
考虑可以生成的 01 子串对应的 a 序列有哪些要求(为方便描述,原 01 串的 a 序列用 A 表示)。
a 序列的生成方式就是 A 删除一些位置,并将保留的数字任意减小。删除一个数的含义是指不仅删除两个 1 之间所有的 0,还把 1 给删掉(在某一侧 0被删完时,1 也可以被删除,前提是删 0 的那一侧不是首部或末尾)。首部和末尾的 0,可以删除任意个,删除之后对原串没有任何影响,最终答案乘上两端 0 的数量单独处理。
对于中间,考虑本质不同的 a 序列有多少种。如果用上段提到的生成 a 序列的方式,会出现很多重复,很难容斥,不利于计算本质不同的数量,我们换个思路,哪些序列是可以被 A 生成的。
一个任意的序列 b,我看它能否被 A 生成,只需要从左到右,每一个数寻找第一个大于等于它的数。既然能保证它是合法的,那就让匹配的位置尽量靠左以腾出更多的数进行匹配,这个贪心是显然正确的。那么 a 序列的集合就是所有合法的 b 的集合,我们 dp 求出在这个贪心下可以存活多少本质不同的 b 序列。
表示序列当前匹配到 A 的第 i 个数字,b 的这个位置填 j 的合法 b 序列个数。匹配到 A 的第 i 位,不一定是 b 的第 i 位,因为中间可能空了几个位置,也就是从 A 的位置 k 转移过来,空出来的位置一定满足:。同时还要保证 ,这个位置得填的下 j 。
枚举 A 的每一位,再枚举这一位填哪个数字 j ,上一个位置 k 是由 j 决定的,中间的 x 求和可以用前缀和优化,总复杂度就是 A 数列之和 O(n)。事实上 dp 数组也不需要第二维的 j ,表示成和就好了。k 是怎么由 j 决定的呢,用一个 lst 数组记录每一个数字最后一个能放下的位置即可。
最后的最后,记住 A 序列是基于 01 串中有 1 才存在的,纯 0 的输入需要特判。
__EOF__

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通