o_o 当前时间是:

4:02:21 AM

 

ARC159F

传送门

solution

神仙 dp 题。

下文认为 n 是题目中给定 n 的两倍。

先考虑一个给定的序列是否能被消除的条件。

猜测一下应该是

  1. 序列长度是偶数

  2. 不存在一个数,在序列中出现超过 n2 次,其中 n 是序列长度。

必要性是显然的。我们每次尽可能消出现次数最多的数,如果满足条件 2,那么当然也是可以消完的(消掉两个数后变成了子问题),所以也有充分性。

fi 表示考虑前 i 个数的答案,有转移:

  • f0=1

  • f2k+1=0

  • f2k=i=02k1[2i][chk(i+1,2k)]fichk(l,r) 表示区间 (l,r) 是可消的。

对于第三个式子,固定 2k,从后往前扫,可以顺便维护 chk,时间复杂度 O(n2)

考虑如何优化转移。

打表发现转移没有什么好的性质,每次转移点变化量之和也是不太能接受的大小。

考虑使用 CDQ 分治优化转移(比较突兀哈,zyb 猜的做法,后来发现可以做)。

对于区间 [l,r],设它分成 [l,mid][mid+1,r] 两个区间,由于是从前向后算,先递归求出 [l,mid] 内所有 dp 值,然后考虑区间 [l,mid] 对区间 [mid+1,r] 的贡献。

这样做有很好的性质。

性质:对于所有 [L,R],lLmid,mid+1Rr,可能的出现次数大于区间一半的数的种类只有 O(log(rl)) 个。

对于证明,先考虑一个前置结论:

一个序列任意前后缀的出现次数大于区间长度一半的数的种类只有 O(logn) 个,n 是序列长度。

比较容易看出,就不证了。

[L,R] 相当于 [l,mid] 的一个后缀和 [mid+1,r] 的一个前缀拼起来,这样数的种类也就不超过 O(log(rl)) 个了。

这样就允许我们在计算贡献的时候枚举这样的数了。

注意,这些非法的转移的贡献是负的,要先把所有 i<pfi 贡献到 fp 上,然后在根据下面的做法减去这些非法转移的贡献。

枚举左端点,然后枚举这些数,用数据结构维护贡献。

具体实现流程如下:

下面设区间长度为 m

先处理出来这样的数,去重。可以 O(mlogm) 做到。(log 是去重时排序给的),设有 sz 个这样的数。

设一个这样的数 p 的前缀出现次数是 cp,i,则区间 [l,r] 能因为这个数不合法的条件就是 rl+12<2cp,r2cp,l1,整理得 2cp,l1(l1)<2cp,rr。所以我们不妨给每个数 sz 个权值,数 pi 位置的对应权值就是 2cp,ii。然后开 sz 个差分数组,整个分治区间内的数按照 (2cp,i,i) 第一关键字递增,第二关键字递减(第二关键字递减是为了让 [l,mid] 内的数排到后面,处理 < 号,而不能取等)。再处理出每个数在这 sz 个排序后的数组里的下标。都可以 O(mlogm) 处理好。

枚举不合法左端点,再枚举这 sz 个数,然后在对应的差分数组里做修改,修改是 O(1) 的,枚举是 O(mlogm) 的。

最后把差分数组前缀和一遍,对应 dp 值加上贡献即可。

带上 CDQ 的 log,时间复杂度 O(nlog2n)

细节比较多,而且有点卡常(official solution 是 O(n) 的)。

code

Submission #47182618 - AtCoder Regular Contest 159

posted @   zzafanti  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示