題目的難度顏色使用 Luogu 上的分級,由簡單到困難分別為 🔴🟠🟡🟢🔵🟣⚫。

🔗 ABC439F Beautiful Kadomatsu

Problem Statement

題目簡述

給定長度 NN 的排列 PP。定義序列為 kadomatsu-like 當且僅當「峰」數 xx 大於「谷」數 yy

  • 峰:ai1<ai>ai+1a_{i-1} < a_i > a_{i+1}
  • 谷:ai1>ai<ai+1a_{i-1} > a_i < a_{i+1}

PP 的子序列中有多少個是 kadomatsu-like 的,答案模 998244353998244353

Constraints

約束條件

  • 1N3×1051 \le N \le 3 \times 10^5
  • PP(1,2,,N)(1, 2, \dots, N) 的排列

思路:條件轉換 + 貢獻計算 + 前綴和優化

條件轉換

定義相鄰元素的關係如下:

  • UU(升):ai<ai+1a_i < a_{i+1}
  • DD(降):ai>ai+1a_i > a_{i+1}

而峰(xx)是由「升轉降 (UDU \to D)」產生,谷(yy)是由「降轉升 (DUD \to U)」產生。
若是連續的相同坡度,僅代表持續上升,不會產生新的峰或谷。因此,我們可以將連續的相同坡度視為一段,整個序列的形狀由交替的 UUDD 段組成。

由於峰與谷必須交替出現,其數量關係完全取決於序列是以何種坡度開始,以及以何種坡度結束。所有情況如下:

起始坡度 結束坡度 形狀示意 峰谷關係
UU UU U,D,,D,UU, D, \dots, D, U x=yx = y
DD DD D,U,,U,DD, U, \dots, U, D x=yx = y
DD UU D,U,,D,UD, U, \dots, D, U y=x+1y = x + 1
UU DD U,D,,U,DU, D, \dots, U, D x=y+1x = y + 1

因此,唯有 UUDD 滿足條件。

條件等價

題目要求 x>yx > y,由上表可知僅有 「始 UUDD 的情況滿足。即子序列 aa 需同時滿足:

  1. a1<a2a_1 < a_2
  2. ak1>aka_{k-1} > a_k

這隱含了 k3k \ge 3,因為至少需要一次「升轉降」才能使 x1x \ge 1 (當 y=0y=0)。若 k<3k < 3 則無法形成完整的峰。

枚舉策略

枚舉 P[i]P[i] 做為子序列的 第二項 a2a_2P[j]P[j] 做為倒數第二項 ak1a_{k-1},其中 iji \le j,考慮 a1a_1aka_k、中間元素的選擇方式:

  • a1a_1:索引 <i< i 且值 <P[i]< P[i] 的元素個數,記為 L[i]L[i]
  • aka_k:索引 >j> j 且值 <P[j]< P[j] 的元素個數,記為 R[j]R[j]
  • 中間元素:iijj 之間任選
    • i<ji < j 時有 2ji12^{j-i-1} 種選擇,即 k4k \ge 4 的情況
    • i=ji = j 時有 11 種選擇,即 k=3k = 3 的情況

其中 L[i]L[i]R[j]R[j] 可以使用 Fenwick Tree 預處理。

計算優化

總答案由兩部分組成:

  1. i=ji = j (k=3k=3):中間無元素。
  2. i<ji < j (k4k \ge 4):中間有 2ji12^{j-i-1} 種選擇。

Ans=i=0N1L[i]R[i]+0i<j<NL[i]R[j]2ji1\text{Ans} = \sum_{i=0}^{N-1} L[i] \cdot R[i] + \sum_{0 \le i < j < N} L[i] \cdot R[j] \cdot 2^{j-i-1}

直接計算第二項需要 O(N2)\mathcal{O}(N^2),會超時。
觀察指數項 2ji1=2j12i2^{j-i-1} = 2^{j-1} \cdot 2^{-i},可將與 jj 有關的項移到外層,將第二項重寫為:

j=1N1R[j]2j1(i=0j1L[i]2i)\sum_{j=1}^{N-1} R[j] \cdot 2^{j-1} \cdot \left( \sum_{i=0}^{j-1} L[i] \cdot 2^{-i} \right)

令括號內的部分為 前綴和 Sj=i=0j1L[i]2iS_j = \sum_{i=0}^{j-1} L[i] \cdot 2^{-i}
當我們從 jj 遍歷到 j+1j+1 時,只需將 L[j]2jL[j] \cdot 2^{-j} 加入 SS,即可在 O(1)\mathcal{O}(1) 內更新。

複雜度分析

  • 時間複雜度:O(NlogN)\mathcal{O}(N \log N)
  • 空間複雜度:O(N)\mathcal{O}(N)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from atcoder.fenwicktree import FenwickTree

MOD = 998244353

def solve():
n = int(input())
P = list(map(int, input().split()))
assert len(P) == n

L = [0] * n
bit1 = FenwickTree(n + 1)
for i, x in enumerate(P):
L[i] = bit1.sum(0, x)
bit1.add(x, 1)

R = [0] * n
bit2 = FenwickTree(n + 1)
for i in range(n - 1, -1, -1):
x = P[i]
R[i] = bit2.sum(0, x)
bit2.add(x, 1)

pow2 = [1] * (n + 1)
for i in range(1, n + 1):
pow2[i] = pow2[i - 1] * 2 % MOD
inv2 = [-1] * (n + 1)
inv2[n] = pow(pow2[n], -1, MOD)
for i in range(n - 1, -1, -1):
inv2[i] = inv2[i + 1] * 2 % MOD

ans = 0
for a, b in zip(L, R):
ans += a * b
ans %= MOD

# for i in range(n):
# for j in range(i + 1, n):
# ans += L[i] * R[j] * pow2[j - i - 1]
# ans %= MOD
s = 0
for j in range(n):
if j > 0:
ans += s * R[j] * pow2[j - 1]
ans %= MOD
s += L[j] * inv2[j]
s %= MOD
print(ans)

if __name__ == '__main__':
solve()