題目的難度顏色使用 Luogu 上的分級,由簡單到困難分別為 🔴🟠🟡🟢🔵🟣⚫。
Problem Statement
這是一道互動題。
題目簡述
給定一個長度為 n n n 的排列 P 1 , P 2 , … , P n P_1, P_2, \ldots, P_n P 1 , P 2 , … , P n 。你需要將其排序為 1 , 2 , … , n 1, 2, \ldots, n 1 , 2 , … , n 。
你可以進行操作:選擇兩個索引 x , y x, y x , y (1 ≤ x , y ≤ n , x ≠ y 1 \le x, y \le n, x \neq y 1 ≤ x , y ≤ n , x = y )。
系統會投擲一枚硬幣:
50 % 50\% 5 0 % 機率交換 p x , p y p_x, p_y p x , p y 。
50 % 50\% 5 0 % 機率交換 p n − x + 1 , p n − y + 1 p_{n-x+1}, p_{n-y+1} p n − x + 1 , p n − y + 1 (即 x , y x, y x , y 的鏡像位置)。
操作後,系統會告知實際上交換的是哪兩個索引。
目標是在 ⌊ 2.5 n + 800 ⌋ \lfloor 2.5n + 800 \rfloor ⌊ 2 . 5 n + 8 0 0 ⌋ 次操作內完成排序。
Constraints
約束條件
1 ≤ n ≤ 4000 1 \le n \le 4000 1 ≤ n ≤ 4 0 0 0
∑ n ≤ 2 ⋅ 1 0 4 \sum n \le 2 \cdot 10^4 ∑ n ≤ 2 ⋅ 1 0 4
思路
這是一道構造演算法題目,結合了互動與機率期望值的概念。
核心難點在於操作具有隨機性:選擇 ( x , y ) (x, y) ( x , y ) 進行交換時,有 50% 機率交換 ( x , y ) (x, y) ( x , y ) ,50% 機率交換其鏡像位置 ( n − x + 1 , n − y + 1 ) (n-x+1, n-y+1) ( n − x + 1 , n − y + 1 ) 。
我們的目標是在 2.5 n 2.5n 2 . 5 n 次操作內完成排序。
從這個限制不難推測出,我們需要將陣列分為 n 2 \frac{n}{2} 2 n 對鏡像位置 ( i , n − i + 1 ) (i, n-i+1) ( i , n − i + 1 ) ,逐對解決,且解決每一對的期望操作次數需要為 5 5 5 次 。
對於每一對 ( l , r ) (l, r) ( l , r ) :
寬鬆限制 (Loose Constraint) :首先嘗試歸位 l l l 。此時我們不在乎 r r r 是否被破壞(或者 r r r 本來就還沒排好)。這是一個簡單的幾何分佈,期望需 2 次 操作。
嚴格限制 (Strict Constraint) :當 l l l 歸位後,我們嘗試歸位 r r r 。此時必須保證 l l l 不被破壞(如果隨機到了鏡像交換導致 l l l 錯位,必須修復)。這種情況下的期望需 3 次 操作。
總計每一對需要 2 + 3 = 5 2+3=5 2 + 3 = 5 次操作,平均每個元素 2.5 2.5 2 . 5 次。
嚴格限制下的期望值計算
我們定義狀態 ( S A , S B ) (S_A, S_B) ( S A , S B ) ,其中 0 0 0 代表已歸位,1 1 1 代表錯位。
嚴格限制情境 :假設 A A A 已歸位,但 B B B 需要歸位,初始狀態為 ( 0 , 1 ) (0, 1) ( 0 , 1 ) 。
我們對 B B B 進行操作:
50 % 50\% 5 0 % 機率成功:B B B 歸位,狀態變為 ( 0 , 0 ) (0, 0) ( 0 , 0 ) 。此步花費 1 1 1 。
50 % 50\% 5 0 % 機率失敗(鏡像交換):A A A 被破壞,狀態變為 ( 1 , 1 ) (1, 1) ( 1 , 1 ) 。此步花費 1 1 1 。
雙重錯位情境 :在狀態 ( 1 , 1 ) (1, 1) ( 1 , 1 ) 時,我們操作任一邊(例如 A A A ):
50 % 50\% 5 0 % 機率 A A A 歸位,狀態變為 ( 0 , 1 ) (0, 1) ( 0 , 1 ) 。
50 % 50\% 5 0 % 機率 B B B 歸位,狀態變為 ( 1 , 0 ) (1, 0) ( 1 , 0 ) (對稱於 ( 0 , 1 ) (0, 1) ( 0 , 1 ) )。
令 E 01 E_{01} E 0 1 為從 ( 0 , 1 ) (0,1) ( 0 , 1 ) 到完成的期望步數,E 11 E_{11} E 1 1 為從 ( 1 , 1 ) (1,1) ( 1 , 1 ) 到完成的期望步數。
列出方程式:
E 01 = 1 + 0.5 ( 0 ) + 0.5 ( E 11 ) = 1 + 0.5 E 11 E_{01} = 1 + 0.5(0) + 0.5(E_{11}) = 1 + 0.5 E_{11} E 0 1 = 1 + 0 . 5 ( 0 ) + 0 . 5 ( E 1 1 ) = 1 + 0 . 5 E 1 1
E 11 = 1 + 0.5 ( E 01 ) + 0.5 ( E 10 ) = 1 + E 01 E_{11} = 1 + 0.5(E_{01}) + 0.5(E_{10}) = 1 + E_{01} E 1 1 = 1 + 0 . 5 ( E 0 1 ) + 0 . 5 ( E 1 0 ) = 1 + E 0 1 (利用對稱性 E 01 = E 10 E_{01}=E_{10} E 0 1 = E 1 0 )
將 (2) 代入 (1):
E 01 = 1 + 0.5 ( 1 + E 01 ) = 1.5 + 0.5 E 01 E_{01} = 1 + 0.5(1 + E_{01}) = 1.5 + 0.5 E_{01} E 0 1 = 1 + 0 . 5 ( 1 + E 0 1 ) = 1 . 5 + 0 . 5 E 0 1
0.5 E 01 = 1.5 ⟹ E 01 = 3 0.5 E_{01} = 1.5 \implies E_{01} = 3 0 . 5 E 0 1 = 1 . 5 ⟹ E 0 1 = 3
故嚴格限制 下的期望次數為 3 。
演算法策略
我們將陣列由外向內分為 n / 2 n/2 n / 2 層。對於每一層 ( l , r ) (l, r) ( l , r ) :
優先嘗試將 l l l 歸位(花費 2 次)。
當 l l l 歸位後,嘗試將 r r r 歸位。
如果在嘗試歸位 r r r 的過程中意外破壞了 l l l ,則退回第 1 步。
這樣每一對的期望花費是 5 次。總共有 n / 2 n/2 n / 2 對,總期望次數為:
Total Ops = n 2 × 5 = 2.5 n \text{Total Ops} = \frac{n}{2} \times 5 = 2.5n
Total Ops = 2 n × 5 = 2 . 5 n
這正好符合題目限制 ⌊ 2.5 n + 800 ⌋ \lfloor 2.5n + 800 \rfloor ⌊ 2 . 5 n + 8 0 0 ⌋ 。
複雜度分析
時間複雜度:O ( n ) \mathcal{O}(n) O ( n ) (期望操作次數 2.5 n 2.5n 2 . 5 n )
空間複雜度:O ( n ) \mathcal{O}(n) 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 def solve (): n = int (input ()) A = [0 ] + list (map (int , input ().split())) pos = [-1 ] * (n + 1 ) for i, x in enumerate (A): pos[x] = i def query (x, y ): print (f"? {x} {y} " , flush=True ) u, v = map (int , input ().split()) A[u], A[v] = A[v], A[u] pos[A[u]], pos[A[v]] = u, v for l in range (1 , n // 2 + 1 ): r = n + 1 - l while pos[l] != l or pos[r] != r: if pos[l] != l: query(pos[l], l) else : query(pos[r], r) print ('!' , flush=True ) if __name__ == "__main__" : t = int (input ()) for _ in range (t): solve()
寫在最後
PROMPT