zoukankan      html  css  js  c++  java
  • [CTSC2008]图腾totem

    (图腾这题做的我头疼 233)

    记 f(xxxx) 为 xxxx 出现的次数,那么题目就是要求 f(1324) - f(1243) - f(1432)

    最有难度的是把上面的式子转化一下,变成 f(1x2x) - f(14xx) - f(12xx) + f(1234)

    这点除非对 f 的求法能一眼看出来,否则很难想到

    后两个比较简单一点

    f(1234) 可以想到用动规求

    具体来讲,设 dp[i][j] (i≤n, 1≤j≤4) 表示第 i 个数后面接 j 个上升序列

    这样转移就是 dp[i][j] = dp[k][j] + dp[k][j-1],其中 k 是一个满足 a[i] < a[k],i < k 的下标,k 可以用线段树求

    然后就是求 f(12xx)了

    利用类似的求法,首先维护一下每个点右边有多少点大于自己,这点用树状数组即可

    然后维护一下上面的前缀和,这样就可以计算 f(12xx) 了

    也就是用两层树状数组

    至于 f(1x2x) 的求法理解起来并不难

    按照高度从小到大把每个点放到原序列中去,不妨设当前点是 2

    可以确定空位置比当前点大,而且当前点比之前放入的点大

    那么为了使用计数原理需要求出空位置的数量

    既然之前的点都比当前点小,假设左边点的下标集合为 S,当前点为 j

    对于 S[i],我们希望知道 S[i] 到 j 有多少空位置

    联想到区间和,又可以用树状数组啦

    当然 |S| 可能会很大,既然这样干脆再套一层树状数组得了

    这样就求出 f(1x2x) 了

    f(14xx) 就变得玄学一点了

     利用类似上面的思想,把原序列从左到右放入一个排好序的序列

    假设当前的是 4,那么排序序列里 4 左边的数都是 1

    中间的空白就是原序列后面的 xx

    然后假设 1 的下标是 i,4 的下标是 j,需要求 (j-i) * (j-i-1) / 2

    也就是 (j-i) * (j-i) - (j-i)

    令 r[i] 表示下标为 i 的数右边空白的数量

    那么上面的式子就是 (r[i] - r[j]) ^ 2 - (r[i] - r[j])

    拆开, r[i] ^ 2 + r[j] ^ 2 - 2 * r[i] * r[j] - (r[i] + r[j])

    考虑左边的所有 1,那么要求的就是 sum { r[i] ^ 2 - r[i] } - sum { r[i] } * r[j] * 2 + ( r[j] ^ 2 - r[j] ) * ( #1 )

    于是维护 r 与 r ^ 2 的区间和就好了

    这题就这样解决啦

  • 相关阅读:
    【leetcode】538/1038: 把二叉搜索树转化为累加树
    k8s-nginx二进制报Illegal instruction (core dumped)
    k8s-记一次安全软件导致镜像加载失败
    Ubuntu1804下k8s-CoreDNS占CPU高问题排查
    Ubuntu 18.04 永久修改DNS的方法
    NLP资源
    《转载》14种文本分类中的常用算法
    PyCharm 使用技巧
    python模块包调用问题
    强化学习(8)------动态规划(通俗解释)
  • 原文地址:https://www.cnblogs.com/HailJedi/p/9302278.html
Copyright © 2011-2022 走看看