1. 程式人生 > 其它 >P4443 [COCI2017-2018#3] Dojave 題解

P4443 [COCI2017-2018#3] Dojave 題解

P4443 [COCI2017-2018#3] Dojave 題解

前言:

不知道為什麼都用的雜湊,我的優化暴力全都均攤了,直接最優解(


簡要題意:

給定 \(m\)\(0\sim 2^m-1\) 的全排列 \(a_i\),問有多少子區間滿足交換兩個不同位置後,整個區間異或和為 \(2^m-1\)

\(m\le 20\)


分析:

正難則反,考慮求出不合法的區間個數。

以下記 \(n=2^m-1\)

結論:

若區間內異或和為 \(0\),並且可以兩兩配對使得兩兩異或和為 \(n\),則這個區間不合法。

證明:

首先如果區間異或和已經為 \(n\),那麼只需要交換區間內或區間外的兩個數即可。

否則,設區間 \(S\)

的異或和為 \(t\)

那麼就是找一對 \(i,j\) 使得 \(i\oplus j=t\oplus n(i\in S,j\notin S)\),不難看出 \(i,j\) 一定是成對出現的,那麼若想要不合法,唯一的可能是集合內兩兩配對的異或和為 \(t\oplus n\)

問題轉化為找到這種情況。

奇數長度的一定合法,因為一定能找到一個數,和它配對的在區間外。

對於偶數長度的情況,如果配對數量為奇數,不妨以三個為例,有:

\[(t\oplus n)\oplus (t\oplus n)\oplus (t\oplus n)=t\oplus n\ne t \]

由於 \(n\ne 0\),顯然不存在這種情況。

配對數量為偶數的,不妨以兩個為例,有:

\[(t\oplus n)\oplus (t\oplus n)=0=\!\!\!\!?\ \ t \]

也就是說,當 \(t=0\) 時這個區間不合法,那麼兩兩配對的異或和就是 \(n\) 了。

至此證畢,下面考慮統計。

定義 \(link_i\) 表示與 \(a_i\) 配對的數的位置,即 \(pos_{n\oplus a_i}\)

對於區間 \([l,p]\)\([p+1,r]\),如果這兩個區間都不合法,則 \([l,r]\) 也一定不合法,這點通過結論不難看出,那麼我們只需要找對於每個點最近的不合法位置在哪裡即可。

考慮一個最暴力的拓展方法,列舉一個左端點 \(l\)

,那麼右端點 \(r\) 至少應在 \(link_l\),下面判斷這個區間是否合法。

  • 如果 \(\exists\,p\in[l,r],link_p<l\),即區間記憶體在一個數,與其配對的數在 \(l\) 左邊,那麼直接跳出,因為我們欽定了 \(l\) 為左端點。
  • 如果 \(\exists\,p\in[l,r],link_p>r\),那麼更新 \(r=link_p\),再重複這個過程,直到跳出或者 \(\forall\, p\in[l,r],l\le link_p\le r\),即區間內兩兩配對。

這樣的暴力做法可以找到每個最短的不合法區間,利用雙指標可以在 \(O(n^2)\) 的時間內求出,下面考慮優化。

注意到我們暴力跳右端點的時候,跳出或者更新答案的點都是區間 \(link\) 最小值或最大值,那麼就可以在 \(O(mn)\) 的時間內預處理出 \(link\) 的 ST 表實現 \(O(1)\) 更新。

之後對於每個點暴力跳的複雜度就變成了均攤 \(O(1)\) 的,簡要證明如下:

對於每一對匹配 \((i,link_i)\),設 \(i<link_i\),那麼當左端點列舉到 \(i\) 的時候看起來會很暴力的一直跳過去,極限狀態下單次 \(O(n)\),但當左端點列舉到 \(link_i\) 的時候,右端點 \(i<link_i\) 會直接跳出,所以實際上每一對匹配只會跳一次,均攤 \(O(1)\)

統計同理,暴力列舉左端點,暴力跳最近的不合法區間,由於我們要計算的區間長度必須為 \(4\) 的倍數,那麼只需要統計一路上 \(\bmod 4\) 同餘的個數即可,為了防止算重,對於每個跳到的點標記一下,如果列舉到了標記點直接跳過即可,每個點的時間複雜度同樣是均攤 \(O(1)\)

總時間複雜度為 \(O(mn+n+n)=O(mn)=O(m\times 2^m)\)

contact me on QQ (601585974 布魯)