1. 程式人生 > 其它 >Codeforces Round #755 (Div. 2) 解題報告

Codeforces Round #755 (Div. 2) 解題報告

這裡是 Codeforces Round #755 (Div. 2) 的解題報告,由於本場 A - C 題和 D - F 題的難度差距過大,故直接從 D 題寫起 qwq


CF1584D. Guess the Permutation

Description

給定一個長度為 \(n\) 的排列 \(\{a_n\}\),初始時有 \(a_i = i\)

現在選擇三個正整數 \(i, j, k\),其中 \(i < j - 1, j < k \le n\),然後將 \(a_{i \cdots j - 1}, a_{j \cdots k}\) 這兩個子序列翻轉。現在你需要通過以下方式詢問,來確定這三個數:

每次選擇一個區間 \([l, r]\,(l \le r)\),詢問這個區間的逆序對數。一共有 \(t\) 組資料,每組最多可詢問 40 次。

資料範圍:\(1 \le t \le 100, 4 \le n \le 10^9.\)

Solution

很容易想到通過二分來尋找這三個數的位置。對於整個序列來說,只有 \([i, k]\) 這個區間對逆序對數有貢獻。所以顯然對於左端點為 1 的區間,區間 \([1, k]\) 到區間 \([1, n]\) 的所有區間的逆序對數均為 \(\dbinom{j - i}{2} + \dbinom{k - j + 1}{2}\),而對於右端點比 \(k\) 小的所有區間其逆序對數一定比此值小,所以根據這個性質,我們可以二分出 \(k\)

但是考慮到 \(\lceil \log_2(10^9) \rceil = 30\),所以我們只有一次二分的機會。我們進而發現,對於 \([j, k]\) 這個區間,\(a_k\) 這個數對區間逆序對數的貢獻為 \(k - j\),所以 \([j, k - 1]\) 這個區間的逆序對數比 \([j, k]\) 這個區間的逆序對數少 \(k - j\)。所以我們只需詢問兩次就可以得到 \(k - j\),進一步我們得到 \(j\)。我們知道 \(j\) 以後可以通過同樣方法進行兩次詢問得到 \(i\),顯然這樣我們只需要最多 34 次詢問就可求出答案。

Code

View on github


CF1584E. Game with Stones

Description

\(n\) 堆石子,其中第 \(i\) 堆石子有 \(a_i\) 個石子。每一次你都可以選擇還未被取完的相鄰兩堆石子,從這兩堆石子各取走一個石子。注意如果一堆石子被取完,那麼和這堆石子相鄰的兩堆石子仍然不被認為是相鄰的。當你恰好能按照上述方法將 \(n\) 堆石子全部取完,那麼你就贏得這場遊戲。我們稱一個序列是可以取勝的,當且僅當以這個序列組成的石子堆數量序列進行遊戲可以取勝。對於給定的 \(\{a_n\}\),求出其有多少個連續的子序列是可以取勝的。一共 \(t\) 組資料。

資料範圍:\(1 \le t \le 3 \times 10^5, 1 \le n \le 3 \times 10^5, 0 \le a_i \le 10^9.\)

Solution

我們先考慮如何判斷一個序列是可以取勝的。我們發現最容易導致我們不能取勝的是第一堆石子,如果第二堆石子被取完而第一堆石子沒有被取完則我們不可能贏得這個遊戲。所以我們先取完第一堆石子 \(a_1\),這時第二堆石子就變成了 \(a_2 - a_1\),這時我們發現原問題就變成了去掉第一堆石子的子問題。為了更形式化的描述這個判定性問題,我們設 \(d_i\) 表明依次取完前面的石子後,第 \(i\) 堆石子剩餘的石子數目。根據定義,顯然有 \(d_i = a_i - d_{i - 1}\,(i > 1, d_1 = a_1)\),進而有 \(d_i = a_i - a_{i - 1} + a_{i - 2} - \cdots + (-1)^{i - 1} a_1\)。而對於一個可以取勝的序列,則需要滿足 \(\forall i \in [1, n - 1], d_i \ge 0, d_n = 0\)。但是對於此問題中,石子堆並不是從第 1 堆開始,所以我們還要考慮從第 \(k\) 堆開始的 \(d\) 序列。我們可以設 \(d_{k, i}\) 表明從第 \(k\) 堆為開始,依次取完 \(i - 1\) 堆後,第 \(i\) 堆的石子數目。顯然我們有 \(d_{k, i} = d_{1, k + i - 1} + (-1)^{i - 1}d_{1, k - 1}\)。而若 \(d_{k, i} \ge 0\),則 \(d_{1, k + i - 1} \ge (-1)^i d_{1, k - 1}\),對於相等的情況同理。

綜上所述,所以我們可以計算出第 \(i\) 個位置的 \(d_i\) 後,使用 map 維護前面有多少個合法的位置 \(j\) 滿足 \(d_i = (-1)^{i - j}d_j\),而且容易發現合法的位置是有單調性的,所以我們可以根據奇偶維護 map 中元素的合法性。由於不知道如何具體描述,具體實現可以看程式碼。

Code

View on github


CF1584F. Strange LCS

Description

給定 \(n\) 個有大寫字母和小寫字母組成的字串 \(s_1, s_2, \cdots, s_n\),每個字母最多在同一字串中出現兩次。求這 \(n\) 個字串的最長公共子序列,\(t\) 組資料。

資料範圍:\(1 \le t \le 5, 2 \le n \le 10.\)

Solution

考慮到 \(n\) 很小,顯然可以考慮 dfs,使用 map 記錄每個字串考慮到的位置和該狀態下的最長公共子序列。這個爆搜很好實現,因為我們有強大的 STL。

考慮此演算法的時間複雜度,每次搜尋都要列舉最長公共子序列的下一個字元並判斷是否可行所需要花費的時間為 \(O(n\left\vert \Sigma \right\vert)\)。由於每個字元只會在同一字串中出現兩次,則合法的狀態的數量為 \(O(2^n \left\vert \Sigma \right\vert)\)。故總時間複雜度為 \(O(n \cdot 2^n \cdot \left\vert \Sigma \right\vert^2)\)

Code

View on github