zoukankan      html  css  js  c++  java
  • [NOI Online #2 提高组]子序列问题

    Description

    给定一个长度为 $n$ 的正整数序列 $A$。定义一个函数 $f(l,r)$ 表示:序列中下标在 $[l,r]$ 范围内的子区间中,不同的整数个数。

    现在,请你求出 $sum_{l=1}^nsum_{r=l}^n (f(l,r))^2$。由于答案可能很大,请输出答案对 $10^9 +7$ 取模的结果。

    Solution

    挺有意思的题目。

    比如一个数 $a_i$,它对哪些 $f()$ 是有贡献的呢?

    比如一个集合 $S$,里面包含了两个 $x$,那么我们可以钦定第一个 $x$ 对 $f(S)$ 造成了 $1$ 的贡献,第二个 $x$ 没有贡献。

    所以,当 $lin[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 imes (R-L+1)+ 2v imes sum$(注意这个 $sum$ 是老的);
    • $sum gets sum + v imes (R-L+1)$。

    这时因为比如对于一个数字 $n$,由 $n^2 o (n+v)^2$ 其实就是 $n^2 o n^2 + v^2 + 2nv$,也就是加上了 $v^2 + 2nv$。

    代码就很好写了,注意卡常。

  • 相关阅读:
    js实现左侧弹出效果
    [z]重建索引
    Query to find the eligible indexes for rebuilding
    查询oracle比较慢的session和sql
    [z]根据awr报告查看最慢的sql语句
    有关Oracle统计信息的知识点[z]
    [z]表空间对应文件的AUTOEXTEND ON NEXT指定的值对性能的影响
    [z]dbms_stats.lock_table_stats对于没有统计信息的表分区同样有效
    统计sql
    SQL truncate 、delete与drop区别[z]
  • 原文地址:https://www.cnblogs.com/syksykCCC/p/NOIO2-S2.html
Copyright © 2011-2022 走看看