Atcoder Regular Contest 159 F-Good Division

link

题意:给出长度为2n的序列,问有多少种分割方案,使得每个子段长度为偶数且众数出现次数不大于长度的一半

首先转化一下,考虑众数出现次数大于长度一半的序列,我们用这个众数去找到这样的序列(注意到一个不合法序列不会被重复统计)

于是可以枚举每个数字(设为col),把序列中等于col的位置设为1,其他设为-1,这样前缀和会形成如下折线:

 那么,右端点为i的不合法区间,它的左端点就是红线以下的位置:

但是这样的位置是很多不连续段,不好直接统计,于是可以考虑上图的j位置,那么i对应的不合法左端点集合,就是j对应的集合(可能需要并上[i, j]这一段) 

这样,就可以从i向j连边,在图上进行dp

中间有一些细节和证明如下(有些加一或减一在此忽略了,这是大概思路):

1.边的条数为O(n) :注意到对于每种颜色col,边(i, j)满足i或j位置上为col,这样,点对(i, j)只有O(col出现次数)条,总共就有O(n)条

2.每个位置需要拆成对应每个颜色的点:即对于每个颜色col,如果位置pos出现在某条边内,就给他新建一个点(由1可知,最后只会拆出来O(n)个点)

3.如何快速找到i对应的j:注意到这个过程类似于括号匹配,可以通过不断删除相邻的1,-1来实现,具体来说,对于每个颜色col,用一个双向链表,从前往后,从后往前每个颜色为col的位置分别扫一遍,不断删除,并找到边(i,j),最后撤销就行,总复杂度O(n)

总的时间复杂度O(n)/O(nlogn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值