看了下賽程,大概只能打 Round 1 和 Round 2 了,之后可能就退役了。
Contest #1
打的時候因為有點事,大概只打了一個多小時。現在終於有時間補完了。
題對於知識點完備的選手比較簡單。我顯然不是這樣的選手,做做就當學點東西了。
C、D、E 題代碼可以翻 LOJ,其他三題有需要可以聯系我。
A - Ljeto
直接模擬即可。
B - Kamenčići
博弈題。\(n\le 350\),比較小,可以考慮一個大概不超過 \(O(n^3)\) 的 dp。
考慮一個狀態有三個要素:左右端點和,以及共取了多少個紅色石子(只需要記錄一個人的,因為另一個以及可以據此確定)。
那么定義:\(f(l, r, c)\) 表示當前操作者面對的局面是,之前以及取過 \(c\) 個紅石子,現在剩下了區間 \([l,r]\),是否有必勝策略。
根據必勝必敗態定理得到轉移:\(f(l, r, c) = \lnot f(l+1,r, c') \lor \lnot f(l,r,c')\)。\(c'\) 是計算得到的對方取過的紅石子數。
復雜度 \(O(n^3)\)。據說可以分析性質得到 \(O(n^2)\) 解法,可以到 cf 看看。
C - Logičari
第一次寫基環樹題!做法可能不是最簡潔的。
題意簡述:對基環樹黑白染色,要求每個點相鄰恰好一個黑點。求最小可能黑點數。
先轉化為正常的樹:任意找一條環邊 \((a, b)\) 斷開,然后欽定一下斷開的邊兩端的四種顏色組合。
不妨設 \(a\) 為根,每個點四個狀態,記錄自己和父親的顏色選擇。然后做正常的樹形 dp。
但是 \(a, b\) 兩個點需要是特殊處理的。對於 \(a\),可以試做它的父親為 \(b\)。而對於 \(b\) 需要額外討論一下……具體細節就不展開了。
復雜度 \(O(n)\)。
D - Set
一下所有數字默認減一(\(\{1, 2, 3\}\to \{0, 1, 2\}\))。
我們挖掘一下題目的性質:對於一個位的三個數字 \((a,b,c)\),其所有合法組合對應的數字加起來都是三的倍數,即 \((a+b+c)\bmod 3 = 0\)。
考慮到本質不同三元組個數為 \(3^m\),設 \(f[i]\) 表示 \(i\) 三進制表示對應的 \(m\) 元組的個數(\(f[i]\in \{0, 1\}\))。
題目要求選取的三個 \(m\) 元組 \(i,j,k\) 的每一位都滿足三進制不進位加法(\(\oplus_3\))為 \(0\),那么就是 \(i\oplus_3 j \oplus_3 k = 0\)。
考慮卷積,下標用上面的 \(\oplus_3\),那么最后 \(f\) 自己卷自己三次后 \(f'[0]\) 就是答案。可以用 3 進制 FWT 實現。
E - Volontiranje
有一個傳統的流做法,但是應該只能跑 subtask 2。
考慮一個基於貪心的神奇結論:在所有備選 LIS 中,抽出一個反轉后字典序最小的必然不劣。
首先感性理解比較真,意識流 證一下也不難:考慮有兩組 LIS:\(\{i_1,i_2, \cdots,i_k\}, \{j_1,j_2, \cdots,j_k\}\),那么我們對應項小的換到 \(i\),大的換到 \(j\),即用 \(\{\min(i_1, j_1),\min(i_2, j_2), \cdots,\min(i_k, j_k)\}, \{\max(i_1, j_1),\max(i_2, j_2), \cdots,\max(i_k, j_k)\}\) 取代之,不難發現其仍然合法。這個方法可以對一個解集在解之間做調整。但是如果最小的那個本身不被該解集包含,則我們可以不要這個解集,而必然存在另一個“可以向小調整”的解集。(看我題解很難沒有疑問(草),想要靠譜點的可以看 cf 或翻官方題解)
然后嘗試實現。直接一次 \(O(n)\) 掃一組解必然不對,考慮先做一次 dp 跑出每個位置結尾的 LIS,然后按 dp 值將下標分組。顯然的,同一組的按位置升序排好之后,其值必然遞減。
那么,如果現在需要選 dp 值為 \(i\) 的組中的位置,上一次選了位置 \(x\)。我們先刪去在 \(x\) 之后的元素:易知這些元素在本次不可用,之后也不會起作用。
刪掉一些后,查看最后面的位置 \(y\) ,是否可以接上 \(x\)。如果 \(a_y > a_x\),那么 \(x\) 就沒辦法用了。需要注意,這不意味着求解結束,而只是將 \(x\) 刪去,\(y\) 可能在枚舉字典序更大的一組解是被使用。因此使用搜索回溯實現。
每個位置用一次就會被刪除,搜索部分復雜度 \(O(n)\)。總復雜度 \(O(n\log n)\)。
Contest #2
A - Kaučuk
簽到
B - Kutije
首先轉化題意,將給定的 \(p_i\) 轉化為圖上的 \(i\to p_i\) 的有向邊。然后每個詢問相當於問是否存在 \(u\) 到 \(v\) 的有向路徑。
觀察到 \(n\le 1000\),我們可以考慮預處理所有的答案。但這張圖是稠密圖,連做 \(n\) 次 DFS 的復雜度是 \(O(n^3)\)。不過我們發現一次 DFS 每個點之后訪問一次,但主要的時間消耗在於找到第一個沒有訪問過的相鄰點。
於是不難想到用 bitset 加速尋找,復雜度 \(O(n^3/w)\)。
草,被自己蠢到了。考慮我們的圖是根據排列生成的,也就是若干個置換環疊合而成。那么很顯然對於一個連通塊(將所有邊取消方向),一定就是一個強連通分量。
於是直接對每個連通塊 DFS 即可,復雜度 \(O(n)\)。
C - Hiperkocka
構造垃圾終於瞎搓成功了!
首先為了讓結構更清晰,我們將這些邊分為 \(n\) 層,根據第 \(k\) 位不同產生的邊放在第 \(k\) 層,每層有 \(2^{n-1}\) 條邊。
根據直覺,我們想辦法讓這 \(n\) 條邊的樹的每一條都用掉一層的一條邊,這樣恰好每層用 \(2^{n-1}\) 次。
第一棵樹是很好構造的,直接從位置 \(0\) 開始 DFS,每次 \(O(n)\) 遍歷最小未使用的層。然后我們發現如果從 \(1\) 直接開始 DFS 構造第二棵樹就可能沖突,不過根據觀察,我們要避開的話,最好是從 \(3\) 開始。
這時你可能發現了,位置 \(0\) 和 \(3\) 除了上面幾層用的邊,其余都是對稱的。這啟發我們倍增地構造一組靠譜的起始點,使得直接在這些位置 DFS 就能出解(並不會證為什么可以這樣,這里如果有人會證可以發個評論)。
考慮從 \([0, 4)\to [4, 8)\),如果同樣用對應的位置 \(4,7\) 的話會沖突,而反過來用位置 \(5, 6\) 的話則恰好錯開,同時 \(5, 6\) 構造出的樹也是在低層對稱的,同 \(0,3\) 一樣也不會沖突。
那么不妨嘗試如下算法:初始區間 \([0,2)\) 中 \(0\) 為起始點,然后復制一份,將是否為起始點狀態取反,接在后面。
然后對於每個起始點都搜出一棵即可。
D - Magneti
考慮一個確定的 \(n\) 個磁鐵的排列,設要使其不互相吸引的最小長度為 \(d\)(即盡量貼近),我們要將其放置在長度為 \(l\) 的槽中,根據插板法不難得到有 \({l-d+n \choose n}\) 種方法。
那么解題的方向就是,對於 \(d=1, 2, \cdots, l\) 分別計算對應的排列方案數,最后乘上組合數系數求和即為答案。官方解法給出了一個漂亮的動態規划方法:
首先將磁鐵按磁力半徑 \(r\) 升序排序,然后定義 \(dp(i, j, k)\) 表示放置前 \(i\) 個磁鐵,分為 \(j\) 組,每組的最小長度之和 \(=k\) 的方案數。這樣的好處是利用了升序排序后,只需要考慮當前的磁力范圍而不需要考慮之前的擺放。因此新的長度和 \(k'\) 可以很方便的計算,從而實現組之間的操作即,dp 的轉移:
- 第 \(i\) 個磁鐵單獨成為一個新的組:\(dp(i-1,j,k) \to dp(i,j+1, k+1)\);
- 第 \(i\) 個磁鐵貼在某個組的端點:\(dp(i-1,j,k)\times 2j \to dp(i, j, k+r_i)\);
- 第 \(i\) 個磁鐵連接了兩個組:\(dp(i-1,j,k)\times j(j-1) \to dp(i, j-1, k+(2r_i-1))\)。
dp 部分復雜度為 \(O(n^2\times l)\)。
這里的狀態設計的巧妙之處還在於分組思想:(摘自 CF)This idea is usually used when trying to construct permutations with certain properties.
E - Osumnjičeni
草,賽后發現是 sb 題,但是 C 題搞太久了……
考慮答案的計算方法是確定的:對於詢問 \([l,r]\),我們從 \(l\) 開始,找到一個最大的 \(i\le r\),滿足 \(l\sim i\) 號身高區間全部不交。那么下一次從 \(i+1\) 開始重復操作即可。最后答案就是操作的輪數(可能反過來再做一次)。
第一是預處理右側最遠的合法位置。考慮建立以身高(離散化)為下標的線段樹,從 \(1\) 掃到 \(n\)。每次查詢當前身高區間中的最大值,然后在這個區間做區間賦值。最后做一遍后綴最小值。
第二是快速跳轉。不難發現這個可以倍增加速。
最后復雜度 \(O(n\log n)\)。