CF1858 D,E题解

D:

比赛临死时交了个假做法MLE了,很气,赛后发现WA了所以安心了。

题意: 给你一个 01 串,你可以最多修改 k 个位置,修改完后最长的 0 串和最长的 1 串记为 len0len1,对于 a1n 的所有取值,输出 alen0+len1 最大值。(n方)

又是 ax+y 的形式,曾经牛客多校也是有一道李超线段树写成了排序的假做法,WA完这道题才发现。

这题可以 n2,因此无需李超线段树,可以枚举 y 来求最大值,那么发现 y 最大是 n ,对于每个 ydp 数组存最大的 x 即可。

我的假做法的预处理和正解一样,处理 f0[i][j] 表示前 i 个位置换 j1 最长的 0 串,f1[i][j] 表示前 i 个位置换 j0 最长的 1 串, g0g1 同理,是后缀最大值。其实这样预处理完,dp 数组扫一遍就能求出来,我却傻乎乎去拿 x 排序。

还有一个和题解不太一样的地方,题解只算了 f0g0,不用算 f1,g1,因为 len1 直接枚举区间就好了,枚举 len1 的区间,就能知道这个区间需要改 j 个位置,然后前缀和后缀改 kj 个位置最大的 len0 去更新 dp 数组即可。

code

E:

参考了SpaceJellyfish佬在群里讨论的 O(n) 做法,代码短且快,理解起来需要多考虑一些情况。

题意: 四个操作,1:数列末尾加一个数。2:数列末尾删除k个数。3:撤销上一个1或2操作。(没有撤销3操作这种duliu挺好)。4:询问数列中不同数字个数。

经典的求不同数字个数,如果题目中左端点固定,或者可以 n2 枚举左端点,那我们一般用 f 数组记录每个数字第一次出现的位置。

在此题中,我们设 a 数组表示当前数列,b 数组取值 01 表示 i 位置是否是第一次出现的位置,那么 b 数组的前缀和 sum 就是要输出的答案哩。我们不用主席树而是只用一个线性的结构来记录答案,那么对于各个版本,如果修改的内容不多,我们可以记录修改的内容然后在撤销时返回即可。

观察此题的撤销操作和删除操作,我们发现操作形成的痕迹是一颗平躺着的树,从左往右长。删除是回到树上某个祖先,撤回删除操作即回到叶子处,这个祖先到叶子的路径其实都是我们当前线性结构储存的信息,我们只需要知道当前的位置 r ,这个到祖先或到叶子其实只是改变 r 的位置,sum 数组不变,sum[r] 一直是答案。添加操作则是生成一个新的枝条,因为我们用的是一个线性的储存结构,这个操作会覆盖掉树上之前的一些信息,当我们撤销添加操作时,覆盖掉的信息更新回来即可。

现在要解决的两个问题:怎么更新添加一个数的信息,覆盖了哪些原来的信息。

添加一个数,只需要考虑这个数 x 是不是第一次出现,f[x]0 当然是第一次出现,但 f[x] 有值时,虽然记录了 x 第一次出现的位置,但是由于 f 可能是之前版本的 f ,在删除操作之后,f 的位置指向了当前位置的后面,或者 f 位置在当前位置前面,但是那个位置已经被新版本给改成其他数字了,这种情况下 x 其实都是第一次出现。

覆盖了哪些信息呢?新位置 r 需要存当前的答案 ans,那么之前的 ans 被覆盖了,从 f 更新过程来看,a 数组也是需要存的,同样被覆盖了,然后还有一个 f[x] 也被修改了,如果我们撤销这个 x 的添加,f[x] 之前应该是另外一个位置。

用栈存操作时顺便记录下这个操作覆盖的这三个原有信息,更新回来即可。

code 短小可爱


__EOF__

本文作者枫叶晴
本文链接https://www.cnblogs.com/maple276/p/17636163.html
关于博主:菜菜菜
版权声明:呃呃呃
声援博主:呐呐呐
posted @   maple276  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示