注:本题解看似很长其实是非常详细,实则思路简单粗暴,容易理解
暴力优化
最暴力的做法即为枚举每一对 $l$ , $r$ ,并分别计算其 $f(l,r)$ 的值。但这样不知道会慢到哪里去了,所以我们考虑只滚动 $l$ 的值,并每次计算 $G(l)=\sum_{r=l}^{n} f^2(l,r)$ 的值。
转移
考虑 $G(l)$ 如何从 $G(l-1)$ 转移过来,由 $G$ 的定义:
$$ \begin{aligned} G(l-1)&=&f^2(l-1,l-1)+&f^2(l-1,l)&&+\cdots +f^2(l-1,n)\\ G(l)&=&&f^2(l,l)&&+\cdots +f^2(l,n) \end{aligned} $$不难发现, $G(l)$ 与 $G(l-1)$ 的唯一区别在于 $G(l)$ 中的每个 $f()$ 的值都少考虑了 $A_{l-1}$ ,即:
$$ \begin{aligned} f(l-1,l-1)&\rightarrow0\\ f(l-1,l)&\rightarrow f(l,l)\\ f(l-1,l+1)&\rightarrow f(l,l+1)\\ f(l-1,l+2)&\rightarrow f(l,l+2)\\ &\vdots \end{aligned} $$( $f(l-1,l-1)$ 彻底没了)。
所以为了计算 $A_{l-1}$ 对哪些 $f$ 有影响,我们可以先预处理出一个数组 $suf[i]$ ,表示 $A_x=A_i$ 且 $x>i$ 时, $x$ 的最小值(如果找不到这样的数,则 $suf[i]=n+1$ )。
在从 $G(l-1)$ 转移到 $G(l)$ 的过程中, $A_{l-1}$ 的消失只对 $f(l-1,l-1\sim suf[l-1]-1)$ 有影响(会-1),因为 $f(l-1,suf[l-1]\sim n)$ 中,都有超过两个与 $A_{l-1}$ 相等的元素,所以即使 $A_{l-1}$ 消失了,这些区间内数字的种类数也不会变。
即:
$$ f(l,r)=\left\{ \begin{aligned} &f(l-1,r)+1&&(r\in[l-1,suf[l-1]-1])\\ &f(l-1,r)&&(r\in[suf[l-1],n]) \end{aligned} \right. $$这样,我们就可以通过线段树维护 $f(l-1,i)$ ,在 $\log(n)$ 的时间内,将每一个 $f(l-1,i)$ 转移成 $f(l,i)$ (区间修改)。
但是这题答案要求的是 $f$ 的平方和,怎么办?
由前缀和维护平方和
(推导类似数学归纳法)
对于 $f(l-1,r)$ ,如果 $f(l,r)=f(l-1,r)-1$ 那么
$$ \begin{aligned} f^2(l,r)&=(f(l-1,r)-1)^2\\ &=f^2(l-1,r)-(2f(l-1,r)-1) \end{aligned} $$又因为
$$ \begin{aligned} G(l-1)-G(l)=(f^2(l-1,l-1)&-0)+\\ (f^2(l-1,l)&-f^2(l,l))+\\ (f^2(l-1,l+1)&-f^2(l,l+1))+\\ &\vdots\\ (f^2(l-1,n)&-f^2(l,n)) \end{aligned} $$又因为刚才推出 $r\in[suf[l-1],n]$ 时, $f(l-1,r)$ 与 $f(l,r)$ 相同,所以式子中许多项被消掉了(式子中的 $n$ 变成了 $suf[l-1]$ )
$$ \begin{aligned} G(l-1)-G(l)=(f^2(l-1,l-1)&-0)+\\ (f^2(l-1,l)&-f^2(l,l))+\\ (f^2(l-1,l+1)&-f^2(l,l+1))+\\ &\vdots\\ (f^2(l-1,{\color{red}{suf[l-1]-1}})&-f^2(l,{\color{red}{suf[l-1]-1}})) \end{aligned} $$又由于第二部分的结论( $r\in[l-1,suf[l-1]-1]$ 时,$f(l-1,r)=f(l,r)+1$ )和这部分开头的结论,式子可以再次化简:
$$ \begin{aligned} G(l)-G(l-1)&=&-(2f(l-1,l-1)&-1)\\ &&-(2f(l-1,l)&-1)\\ &&-(2f(l-1,l+1)&-1)\\ &&&\vdots\\ &&-(2f(l-1,suf[l-1]-1)&-1)\\ &=&-2\times\sum_{r=l-1}^n f(l-1,r)+((suf[l-1])&-(l-1)+1) \end{aligned} $$这个值可以直接用刚才维护 $f$ 的线段树来算出。
最终做法
伪代码:
|
|
最终代码:(除去线段树极其简短)
|
|
易错点
- 随时%p,如果不开 long long 小心越界
- 计算 $suf[i]$ 的时候如果用类似桶排序的方法要离散化
- 线段树中查询和修改操作要判断查询的区间是否合法,如果否,要直接退出(本题解中,为了写得更加方便, $suf[i]$ 的定义比较特别(如果找不到这样的数,则 $suf[i]=n+1$ ),所以如果不特判可能会re)
- 线段树数组大小