[NOI Online #2 提高组]子序列问题
Description
给定一个长度为 $n$ 的正整数序列 $A$。定义一个函数 $f(l,r)$ 表示:序列中下标在 $[l,r]$ 范围内的子区间中,不同的整数个数。
现在,请你求出 $\sum_{l=1}^n\sum_{r=l}^n (f(l,r))^2$。由于答案可能很大,请输出答案对 $10^9 +7$ 取模的结果。
Solution
挺有意思的题目。
比如一个数 $a_i$,它对哪些 $f()$ 是有贡献的呢?
比如一个集合 $S$,里面包含了两个 $x$,那么我们可以钦定第一个 $x$ 对 $f(S)$ 造成了 $1$ 的贡献,第二个 $x$ 没有贡献。
所以,当 $l\in[last_{a_i} + 1, i], r \in[i, n]$ 时,$a_i$ 被包含进了区间内,且 一定是第一个这种数,所以它会对这些 $f(l, r)$ 都造成了 $1$ 的贡献。
那么这时候我们就可以开一个平面了,横轴表示 $l$,纵轴表示 $r$,每次把横坐标在 $[last_{a_i} + 1, i]$,纵坐标在 $[i, n]$ 的这个矩形的每个元素的权值 $+1$,最后的答案就是每个元素的值的平方和。
难道是二维线段树/树套树?空间显然是不够的。
这时候难道要用扫描线了吗?当然不是,太麻烦了。
我们沿用扫描线的思想,观察一下这些矩形有什么特点。
我们发现,第 $i$ 个矩形的纵坐标下端点是 $i$,上端点是 $n$,那么我们如果使用水平扫描线的话,所有的 $-1$ 标记都是在平面的顶端,所以,我们可以忽视所有的 $-1$ 标记。
于是,题目就变成了,$i$ 次,每次先把 $[last_{a_i}+1, i]$ 的位置的权值 $+1$,然后查询全局平方和,发现这个用一维线段树是很好维护的。
具体实现细节的话,读入进来的 $a_i$ 首先要离散化,然后按照上面的进行就行了,至于线段树怎么维护区间加,全局平方和,可以考虑维护区间和 $sum$ 和区间平方和 $sum_2$,比如现在要把 $[L,R]$ 这一段都 $+v$,其实就是:
- $sum_2 \gets sum_2 + v^2 \times (R-L+1)+ 2v \times sum$(注意这个 $sum$ 是老的);
- $sum \gets sum + v \times (R-L+1)$。
这时因为比如对于一个数字 $n$,由 $n^2 \to (n+v)^2$ 其实就是 $n^2 \to n^2 + v^2 + 2nv$,也就是加上了 $v^2 + 2nv$。
代码就很好写了,注意卡常。