[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 的区间和就好了

这题就这样解决啦

posted @ 2018-07-13 12:40  蒟蒻lrz  阅读(188)  评论(0编辑  收藏  举报