洛谷 - P4062 [Code+#1]Yazid 的新生舞会(推公式+线段树)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 - P4062 [Code+#1]Yazid 的新生舞会(推公式+线段树)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出一个长度为 n n n 的序列,现在要求存在 绝对众数 的子区间个数

所谓 绝对众数,就是对于区间 [ l , r ] [l,r] [l,r] 来说,存在一个数字的出现次数 c n t cnt cnt,满足不等式 c n t ∗ 2 > r − l + 1 cnt*2>r-l+1 cnt2>rl+1

题目分析:假如字符集很小,我们可以对每个字符集单独讨论,即枚举每个字符作为众数,判断合法的区间个数。如何判断?设置一个辅助数组 b b b,若原数组的 i i i 位置是该字符,则令 b [ i ] = 1 b[i]=1 b[i]=1,否则 b [ i ] = − 1 b[i]=-1 b[i]=1,对 b b b 数组维护一个前缀和 s u m sum sum,不难看出区间和严格大于 0 0 0 的区间是合法的区间,即需要寻找合法二元对 ( i , j ) (i,j) (i,j) 的个数满足 s u m [ i ] < s u m [ j ] sum[i]<sum[j] sum[i]<sum[j] i < j i<j i<j。不难看出这就是基于 s u m sum sum 的一个顺序对。可以用树状数组简单维护,时间复杂度 O ( k n l o g n ) O(knlogn) O(knlogn) k k k 为字符集大小。

但是对于本题而言,字符集特别大,和 n n n 同阶,所以考虑优化。

如果对于每个字符都继续沿用上述过程求解的话,我们发现 b b b 数组中绝大部分都是 − 1 -1 1,且 ∑ 1 = n \\sum1=n 1=n

b b b 数组中 − 1 -1 1 特别多的情况自己手玩一下,发现对于前缀和 s u m sum sum 而言,假设 a [ s t ] = a [ e d ] a[st]=a[ed] a[st]=a[ed],且区间 ( s t , e d ) (st,ed) (st,ed) 不再有 a [ i ] = a [ s t ] a[i]=a[st] a[i]=a[st] 的位置 i i i,那么 s u m [ s t : e d ] sum[st:ed] sum[st:ed] 将会是一个公差为 − 1 -1 1 的等差数列。

我们最终的目的仍然是需要求解“顺序对”的个数,所以线段树一定是跑不了的,考虑如何快速用线段树维护这个等差数列,以及计算这个等差数列的贡献。

回顾计算顺序对最朴素的方法:

  1. 枚举每个位置 i i i
  2. a n s + = s u m ( − ∞ : a [ i ] − 1 ] ans+=sum(-\\infty:a[i]-1] ans+=sum(:a[i]1]
  3. a [ i ] a[i] a[i] 放进线段树

假设我们需要维护的等差数列, x x x 的坐标为 [ s t , e d ] [st,ed] [st,ed] y y y 对应的区间为 [ L , R ] [L,R] [L,R],更通俗的讲就是, a [ s t ] = R , a [ s t + 1 ] = R − 1 , . . . , a [ e d ] = L a[st]=R,a[st+1]=R-1,...,a[ed]=L a[st]=R,a[st+1]=R1,...,a[ed]=L

然后我们就很神奇的发现,我们需要维护的这个等差数列,他自己不会提供给自己贡献。具体来说就是,因为对于每个位置 i i i,我们需要统计 s u m ( − ∞ : a [ i ] − 1 ] sum(-\\infty:a[i]-1] sum(:a[i]1],而这个等差数列 i i i 前面的位置都是大于 a [ i ] a[i] a[i] 的,所以并不会提供贡献

所以根据上述朴素的方法,我们可以得到这个等差数列的贡献为: ∑ i = s t e d ∑ j = − ∞ i − 1 s u m [ j ] \\sum\\limits_{i=st}^{ed}\\sum\\limits_{j=-\\infty}^{i-1}sum[j] i=stedj=i1sum[j]

简单推导一下得到:
∑ i = L R ∑ j = − ∞ i − 1 s u m [ j ] = ∑ i = L R ( ∑ j = − ∞ L − 1 s u m [ j ] + ∑ j = L i − 1 s u m [ j ] ) = ( R − L + 1 ) ∗ ∑ j = − ∞ L − 1 s u m [ j ] + ∑ i = L R ∑ j = L i − 1 s u m [ j ] = ( R − L + 1 ) ∗ ∑ j = − ∞ L − 1 s u m [ j ] + ∑ i = L R ( R − i ) ∗ s u m [ i ] = ( R − L + 1 ) ∗ ∑ j = − ∞ L − 1 s u m [ j ] + ( R − L + 1 ) ∗ R − ∑ i = L R i ∗ s u m [ i ] \\begin{aligned} &\\sum\\limits_{i=L}^{R}\\sum\\limits_{j=-\\infty}^{i-1}sum[j]\\\\ &=\\sum\\limits_{i=L}^{R}(\\sum\\limits_{j=-\\infty}^{L-1}sum[j]+\\sum\\limits_{j=L}^{i-1}sum[j])\\\\ &=(R-L+1)*\\sum\\limits_{j=-\\infty}^{L-1}sum[j]+\\sum\\limits_{i=L}^{R}\\sum\\limits_{j=L}^{i-1}sum[j]\\\\ &=(R-L+1)*\\sum\\limits_{j=-\\infty}^{L-1}sum[j]+\\sum\\limits_{i=L}^{R}(R-i)*sum[i]\\\\ &=(R-L+1)*\\sum\\limits_{j=-\\infty}^{L-1}sum[j]+(R-L+1)*R-\\sum\\limits_{i=L}^{R}i*sum[i] \\end{aligned} i=LRj=i1sum[j]=i=LR(j=L1sum[j]+j=Li1sum[j])=(RL+1)j=L1sum[j]+i=LRj=Li1sum[j]=(RL+1)j=L1sum[j]+i=LP4062 [Code+#1]Yazid 的新生舞会(线段树做法)

luogu P4062 [Code+#1]Yazid 的新生舞会(线段树+套路)

BZOJ5110[CodePlus2017]Yazid 的新生舞会 线段树

Yazid的新生舞会(线段树)

bzoj5110[CodePlus2017]Yazid 的新生舞会 Treap

「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)