1. 程式人生 > >ZROI WC Round5 題解

ZROI WC Round5 題解

sub rac 暴力枚舉 線性 之間 clas 減少 這一 一個

ZROI WC Round5 題解

Problem A

題意

給定一個長度為 \(n\) 的序列,操作是交換兩個相鄰的數,要求將序列變成先單調不降再單調不升,求最小操作數,註意可以完全單調不降或者完全單調不升

想法

發現最小的數一定在最左側或者最右側

有一個暴力的做法是按照從小到大的順序,每次看向哪邊比較近就交換到哪一側,由於不管交換到哪一個剩下的序列都是一樣的,所以這個做法是正確的

下面就是優化這個算法,不難發現一個數如果移動到最左側,那麽它左側的比它小的數肯定都移動到左側,所以可以用樹狀數組算出每個數向左或者向右最終的位置,統計一下即可得到答案

Review

有一個錯誤的直觀想法就是認為一定存在一條分界線,然後把兩邊的數排序

它的錯誤在於不能處理一邊排序,一邊仍舊是一個山峰形狀但是山峰和排好序的一邊能夠平起來的情況

這種題一般都考慮最大或最小值的最終位置,考場上我一直在考慮最大值的位置,事實上最大值並不能將序列分成兩部分,所以應當考慮最小值的位置

Problem B

題意

有一個 \(01\) 矩陣,求 \(\sum_{i=1}^{n}\sum_{j=1}^{m}i\times j \times rank(T(A,i,j))\)\(998244353\) 取模的值,其中 \(rank\) 表示矩陣的秩,\(T(A, i, j)\) 表示矩陣 \(A\)\((i,j)\) 這一位翻轉之後的矩陣

題解

有兩種做法,暫時只寫會的一種

考慮暴力怎麽寫,就是直接枚舉每一行,然後把除了這一行以外的玩意全部壓進線性基裏面,然後枚舉這一行每一個位置,把它翻轉,然後往線性基裏面扔,復雜度 \(O(\frac {n^4m} {32})\) (竟然能過 \(n=100\) 的點)

首先不難發現可以分治,這樣就把一個 \(O(n)\) 變成了 \(O(\log n)\)\(solve(l, r)\) 表示詢問第 \(l\) 行到第 \(r\) 行之間的答案,然後就可以先修改一半詢問另一半再撤回修改操作(基礎分治)

這樣復雜度 \(O(\frac {n^3m \log n} {32})\),還是不行,需要跑 \(4\)\(5\)

然後只能考慮在詢問某一行上減少復雜度

我們發現對於某一行,翻轉不同的兩個位置,差距實際上很小

所以我們考慮先不翻轉任何一位,直接塞進線性基裏,然後修改第 \(j\) 位的時候直接和線性基裏面的第 \(j\) 個異或即可

但是這樣可能會錯誤,觀察發現錯誤原因是你和第 \(j\) 位直接異或會導致第 \(j\) 位後面的某些位又變成 \(1\) 了,所以我們需要一個最簡線性基,這並不難實現,我們在每一次插入數的時候,假設插入 \(x\) 在第 \(j\) 位上,我們先把它化簡,就是把這一位之後的位置在線性基裏面跑一遍,盡量異或成零,然後把這一位之前的數化簡,就是如果存在一個更高位對應的數裏面這一位是 \(1\),就跟現在這個數異或,這樣保證每一個位置對應的數都已經盡量滿足除了那個位置都是零,保證了正確性

代碼很簡單


inline void fuck(int dep, int p) {
  rrep(i, p - 1, 1) if (b[dep][p][i] && b[dep][i].any()) b[dep][p] ^= b[dep][i];
  rrep(i, m, p + 1) if (b[dep][i][p]) b[dep][i] ^= b[dep][p];
}

這樣的話,我們沒有辦法撤銷操作,所以我們記錄下每一層的線性基,也就是上面代碼中的 \(b[dep]\)

綜上所述,復雜度 \(O(\frac {n^2m\log n} {32})\),實際上跑的很快,\(n=1000\) 大概跑 \(300 \sim 400ms\)

Review

每個部分都不難,但是合起來有些難度

想法很自然,每個修改內部做到線性的方法很巧妙

Problem C

題意

給定一些集合 \(A_1,A_2,A_3,\dots,A_k\),定義一個集合 \(A\) 能將兩個集合 \(X,Y\) 分離當且僅當滿足以下兩個條件之一:

  • \(X \subseteq A\)\(Y \cap A = \emptyset\)
  • \(Y \subseteq A\)\(X \cap A = \emptyset\)

求有多少個 \(X,Y\) 滿足 \(X,Y \subseteq \{1,2,3,\dots, n\}\) 且滿足至少存在一個 \(A_i\) 能夠將 \(X,Y\) 分離

題解

不難發現是一道容斥題

如果直接暴力枚舉哪些 \(A\) 能夠將兩個集合分離,會存在問題,就是當 \(X \subseteq A\)\(Y \cap A = \emptyset\) 的時候會存在另外一個 \(A\) 未被選擇但是滿足 \(Y \subseteq A\)\(X \cap A = \emptyset\),這樣並沒有辦法去重

所以我們得枚舉哪些集合是 \(X\) 的超集,哪些集合是 \(Y\) 的超集,並且滿足所有 \(X\) 的超集都與 \(Y\) 無交,\(Y\) 的超集與 \(X\) 無交

這樣枚舉完了之後掃一遍看哪些數還能被 \(X\) 選,哪些數還能被 \(Y\) 選,然後算一下就好了,復雜度 \(O(3^m n)\),期望得分 \(70\)

我們假設將所有的 \(A_i\) 分成 \(U\)\(V\),滿足 \(U\) 裏面的 \(A_i\) 都是 \(X\) 的超集,\(V\) 裏面的 \(A_i\) 都是 \(Y\) 的超集,也就是說,如果某個數 \(a\)\(X\) 的一個元素,則 \(a\) 滿足是所有 \(U\) 中集合的元素,而且不是任何一個 \(V\) 中集合的元素,瓶頸在於枚舉 \(U,V\)

我們考慮枚舉 \(a\),對於每一個元素 \(a\),我們預處理出包含 \(a\) 的所有 \(A_i\)\(f(a)\)

這時候我們枚舉 \(S=U+V\),之前的瓶頸在於還得枚舉一個 \(U\)\(S\) 的子集,但是我們發現這樣的 \(U\) 必須滿足是某個元素的 \(f\) 值,所以這樣的 \(U\) 最多只能有 \(n\) 個,同樣 \(V\) 最多也只能有 \(n\) 個,所以復雜度 \(O(2^mn)\),可以通過此題

Review

容易陷入枚舉哪些 \(A\) 能夠將兩個集合分離的誤區,事實上正解也是這個,但是實際上是在枚舉 \(U+V\),本質不同

所以需要先想出 \(70\) 分的暴力,才有希望想到正解,暴力還是比較自然的

ZROI WC Round5 題解