[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 的区间和就好了
这题就这样解决啦