[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 的區間和就好了
這題就這樣解決啦