求长度为
n 序列
a 有多少个子区间的众数出现次数超过了区间长度的一半。
n,ai≤5×105。
我们称在区间中出现次数超过区间长度一般的众数为绝对众数。显然,一个区间至多有一个绝对众数。因此枚举每种权值计算贡献。
记
Sx,i 表示
j=1∑i[aj=x]。考虑一个区间
[l,r] 以
x 为绝对众数的充要条件,显然
Sx,r−Sx,l−1>2r−l+1,整理得
2Sx,r−r>2Sx,l−1−(l−1)。我们记
wx,i=2Sx,i−i,就是要统计满足
wx,r>wx,l 且
0≤l<r≤n 的
(l,r) 对数。将
w 的值域平移至从
1 开始。枚举
r,用数据结构维护
w 的值域前缀
[1,v) 的
l 个数
fv,可以做到
O(n2logn)。
考虑优化,记
x 出现的位置依次为
px,1,…,px,m。同时不妨
px,0=0。我们发现对于
[px,i,px,i+1) 内的
r,它们的
Sx,r 是相同的,因此
wr 呈一段公差为
−1 的等差数列。考虑怎样快速计算每一段的贡献。考虑维护
fv 表示这一段之前所有段的
w 前缀值域
[1,v) 中的
l 个数。
记这一段的等差数列为
wr=k−r,那么这一段的贡献是:
j=px,i∑px,i+1−1fk−j=j=k+1−px,i+1∑k−px,jfj
相当于要查询
f 数组区间和。考虑每一段对
f 数组的影响是什么,记这一段等差数列的值域是
[L,R]。那么对于
[L,R] 内的
v,有
[L,v−1] 这些数可以对
fv 产生贡献,为
v−L;对于
v≥R+1,
[L,R] 内的数都可以对
fv 产生贡献。所以操作形如
f 数组区间加等差数列。用你喜欢的数据结构维护即可。
我使用了树状数组,考虑直接维护
f 数组的前缀和
F 数组,考虑每个操作对
F 产生怎样的影响,手推一下可以发现将
Fi 表示为关于
i 的二次函数,那么每次操作都相当于各次项系数区间加,查询是单点查,就可以树状数组维护了。
认为
n 和值域同阶,时间复杂度
O(nlogn),空间复杂度
O(n)。