IOI 2020 集訓隊作業胡扯「1, 50」(★)
IOI 2020 集訓隊作業胡扯「51, 100」
IOI 2020 集訓隊作業胡扯「101, 150」
如果您點擊了某個超鏈接,但是並沒有發生任何變化,這意味着您可能需要在另外兩章節中尋找對應內容。
表格
綠的表示主要沒看題解,紅的表示主要看了題解。
agc037_e
本題是在獲得集訓隊訓練資料前就已經做過的,故寫在開頭。
令 \(S\) 中的最小字符為 \(c\),考慮最終得到的串,其開頭的連續 \(c\) 的長度必然要最大化。
考慮最初始的 \(U = ST\),\(U\) 中的最長連續 \(c\) 可以放在新的 \(S\) 的開頭或末尾,如果此次操作是最后一次,則放在開頭,否則放在末尾。假設初始的 \(U\) 的最長 \(c\) 連續段長度為 \(L\),這樣一來可以在最終串里構造出長度為 \(\min \{ N, 2^{K-1} L \}\) 的 \(c\) 的連續段。
當連續段長度確定時,再比較之后的字符串的字典序,稍加推導可以發現其實就是初始的 \(U\) 的一個后綴,因為 \(n\) 不大,暴力比較即可。
時間復雜度為 \(\mathcal O (n^2)\),評測鏈接。
agc029_c
本題是在獲得集訓隊訓練資料前就已經做過的,故寫在開頭。
先特判答案為 \(1\) 的情況,然后二分答案 \(m\),其實就是在 \(m\) 進制下找遞增數列,考慮到非 \(0\) 的位置很少,隨便用個 map 或者數組維護一下就行。
之前寫的是用 map 的,重制版用的是數組。
時間復雜度為 \(\mathcal O (n \log n)\),評測鏈接。
agc025_d
本題是在獲得集訓隊訓練資料前就已經做過的,故寫在開頭。
我們可以證明,在所有距離恰好為 \(\sqrt{D}\) 的格點對之間連邊,形成的圖必然是一個二分圖。
當 \(D\) 為奇數時,對格點進行黑白染色然后考慮 \([{(\Delta x)}^2 + {(\Delta y)}^2]\) 為奇數即可得證。
當 \(D\) 為偶數時,正好相反,黑色點之間會相互連邊(白色點同理),將坐標縮小至原來的 \(1 / \sqrt{2}\) 倍,等價於 \(D / 2\) 的情況進行歸納。
對 \([0, 2 N) \times [0, 2 N)\) 中的所有格點進行關於 \(D_1\) 的黑白染色,和關於 \(D_2\) 的紅藍染色。
選取四種顏色搭配中較多的那一種,根據抽屜原理至少有 \(N^2\) 個點。
時間復雜度為 \(\mathcal O (N^2 \sigma_0(N))\),評測鏈接。
2019-10-30
cf516D
時間復雜度為 \(\mathcal O (n \log n + n q \alpha)\),評測鏈接。
cf506C
時間復雜度為 \(\mathcal O ((n + mk) \log w)\),評測鏈接。
2019-10-31
cf555E
容易看出給一張無向圖定向后可以變成強連通圖當且僅當這張圖是一張邊雙連通圖。
將每個邊雙連通分量縮成一個點,在形成的森林上用類似 Tarjan LCA 的方法判斷是否合法。
時間復雜度為 \(\mathcal O (n \log n + m + q)\),評測鏈接。
cf576D
按照需要的次數從小到大考慮每個航班,矩陣快速冪優化轉移,bitset 優化矩乘。
時間復雜度為 \(\displaystyle \mathcal O \!\left( m \frac{n^3}{w} \log d \right)\),其中 \(w\) 為字長,評測鏈接。
2019-11-06
cf512D
先對圖做一個類似拓撲排序 / BFS 的算法,將圖拆成若干無根樹和有根樹(樣例解釋的圖片寫得很清楚),對於每棵樹分別做背包合並即可。
對於有根樹的背包是顯然的,用 \(f(u, i)\) 表示在 \(u\) 的子樹中刪去 \(i\) 個點的方案數,轉移是顯然的樹上背包形式。
對於無根樹,對所有點為根都做一次 DP,考慮所有 DP 值的總和,刪去了 \(i\) 個點的方案數會被重復統計 \(\mathrm{siz} - i\) 次(\(\mathrm{siz}\) 是這棵無根樹的大小,\(0 \le i < \mathrm{siz}\)),所以 \(f(\ast, i)\) 除以 \(\mathrm{siz} - i\) 即可。
時間復雜度為 \(\mathcal O (n^3)\),評測鏈接。
2019-11-08
cf575A
矩陣快速冪 sb 題,有個地方沒開 long long 一直 TLE7。
時間復雜度為 \(\mathcal O (M \log M + (N + M) \log K)\),評測鏈接。
cf547E
本着能用 ACAM 不用 SA,能用 SA 不用 SAM 的指導思想,這題就是 AC 自動機 fail 樹上 DFS 序建樹狀數組裸題了。
時間復雜度為 \(\mathcal O (|\mathbf{\Sigma}| l + (q + l) \log l)\),其中 \(\displaystyle l = \sum |s_i|\),評測鏈接。
cf704B
首先把絕對值拆開,把 \(x_i\) 取或正或負,加到 \(a_i, b_i, c_i, d_i\) 上,就可以把邊的代價轉移到端點上,然后只需考慮每個點進出的方向。
考慮最終的某個完整的路徑,只看前 \(i\)(\(1 \le i < n\))個點的話,會被拆成若干條鏈,有的鏈可能包含起點或終點(不能同時包含)。
令 \(f(i, j)\) 表示前 \(i\) 個點,有 \(j\) 條鏈(不算包含起點或終點的鏈)時的最小代價(只統計前 \(i\) 個點的代價)。
第 \(i + 1\) 個點的轉移就是合並兩條鏈,延伸一條鏈,或者自成一條鏈,對於包含起點或終點的鏈特殊處理一下即可。
時間復雜度為 \(\mathcal O (n^2)\),評測鏈接。
2019-11-09
cf528C
一張連通無向圖能給每條邊定向滿足每個點的入度出度均為偶數當且僅當這張圖存在歐拉回路且邊數為偶數。證明不會,看題解的。
所以先添加邊把奇點兩兩配對,如果邊數還是奇數,就再加個自環。然后求歐拉回路,路徑上的邊方向交替定向即可。
這題題面上沒說保證原圖是連通圖,但是確實是連通的,我也沒話說……
時間復雜度為 \(\mathcal O (n + m)\),評測鏈接。
2019-11-10
cf685C
很顯然可以二分答案,然后把每個曼哈頓距離拆成 \(8\) 個不等式交一下,然后取一個交出的格點即可。
但是,草了,就是解不出來不等式,就是 WA6 了,我有什么辦法?不得不看題解代碼 /cy
時間復雜度為 \(\mathcal O (n \log v)\),其中 \(v\) 是值域,評測鏈接。
cf704C
題目要求的是使得形如 \((x_a \vee \overline{x_b}) \oplus (\overline{x_c}) \oplus \cdots \oplus (x_d \vee \overline{x_d}) \oplus (x_e \vee x_f)\) 的布爾表達式的取值為 \(1\) 的變量賦值方案數。
滿足每個子句 \(\cdots \oplus (x_i \vee x_j) \oplus \cdots\) 僅有 \(1\) 或 \(2\) 個變量,且每個變量在表達式內最多出現兩次(\(x_i\) 和 \(\overline{x_i}\) 的形式均算一次)。
將 \(m\) 個變量抽象為 \(m\) 個節點,把每個形如 \((x_i \vee x_j)\)(或換成 \(\overline{x_i}\) 或 \(\overline{x_j}\))的表達式看作一條連接 \(x_i\) 和 \(x_j\) 的邊。
則有每個節點的度數最多為 \(2\),也就是說整個圖形成了若干個連通塊,每個連通塊要么是鏈要么是環。
如果連通塊是鏈,從鏈的一端遞推轉移,記狀態為當前考慮的變量的取值為 \(0\) 或 \(1\) 時,整體表達式為 \(0\) 或 \(1\) 的取值方案數,每個連通塊轉移完后並入總答案。需要注意的是鏈的兩端(假設為 \(x_i\))可能有形如 \((x_i)\) 或 \((\overline{x_i})\) 的表達式,需要特殊處理。
如果連通塊是環,類似地從環上某個點以某個方向遞推,狀態表示要多起始點的取值為 \(0\) 或 \(1\) 這一維,轉移與鏈類似,每個連通塊轉移完后並入總答案。比鏈的情況方便的是,環上不可能出現形如 \((x_i)\) 或 \((\overline{x_i})\) 的表達式了。
孤立點,或者只有 \((x_i)\) 或 \((\overline{x_i})\) 的節點需要特殊處理。
特別地,如果出現了 \((x_i \vee x_i)\)(或 \(\overline{x_i}\))也需要特殊處理,且該變量 \(x_i\) 不會出現在其它表達式中。
想着好像很簡單,但是越寫越麻,有點自閉。
時間復雜度為 \(\mathcal O (n + m)\),評測鏈接。
2019-11-11
cf536D
先用 Dijkstra 求出 \(s\) 和 \(t\) 到每個點的距離,離散化后值域為 \(\mathcal O (n)\)。
把每個點 \(i\) 表示為平面上的點 \((\operatorname{dis}(s, i), \operatorname{dis}(t, i))\),權值為 \(p_i\)。
轉化為有兩根線,初始時分別在 \(x\) 軸和 \(y\) 軸上,先手操作水平線,后手操作垂直線,每次將線往上 / 右移動且至少經過一個點,獲得經過的點的權值,兩人均最大化自己的收益,問最終兩人的收益。
這是顯然的零和博弈,因為坐標范圍不大,直接 DP 就做完了,就是要用一個后綴 \(\min\) 優化。
時間復雜度為 \(\mathcal O (m \log n + n ^ 2)\),評測鏈接。
2019-11-12
cf674D
感謝出題人保證了沒有長度小於等於 \(2\) 的環,要不然人就沒了。
假設圖是一棵樹,那么有一個常見的套路是修改時只考慮孩子對雙親產生的影響,詢問時加上雙親對自己的影響即可,這樣每次只會改 \(\mathcal O (1)\) 的信息,這里是基環樹也沒什么影響。
這里要實現一個全局極值查詢的操作,考慮到對孩子的修改會導致雙親的度數變化從而導致雙親的其它子節點(兄弟節點)的權值變化,無法直接維護。不過這個變化量是相等的,即雙親節點的度數變化對不同孩子節點的貢獻產生相同的變化。可以考慮對於每個節點維護一個它所有子節點的權值(不算它對子節點的影響)的集合,當子節點權值發生變化或自身度數發生變化時重新維護集合並更新對總答案的貢獻(每個集合只需要貢獻出其最大最小值即可)。
可以發現這樣處理的話,每次改動的集合數量就是 \(\mathcal O (1)\) 的:假設修改的點為 \(i\),將 \(f(i)\) 改為 \(j\),權值(不考慮雙親對孩子的影響)有變化的有 \(f(i)\)(因為 \(i\) 不再是它的子節點了,而且度數變化了),\(f(f(i))\)(因為 \(f(i)\) 的度數變化了,對它的貢獻變化了),\(j\)(理由同 \(f(i)\)),\(f(j)\)(理由同 \(f(f(i))\))。它們的權值變化會影響它們的雙親節點維護的集合的變化,所以還要更新一些集合。
總共有 \(6\) 個要更新的點,其中還有重復的,寫起來比較復雜,先假設 \(i\) 被刪除了,更新 \(f(i)\),\(f(f(i))\) 和 \(f(f(f(i)))\),然后再更新 \(j\),\(f(j)\) 和 \(f(f(j))\) 會好考慮些。
時間復雜度為 \(\mathcal O ((n + q) \log n)\),評測鏈接。
2019-11-13 ~ 2019-11-19
CSP 緩沖周。
2019-11-20
cf568E
怎么看這個 \(k \le 1000\) 都不好用,只能是 \(\mathcal O (k(n + m))\) 了吧,據說 CF 評測機一秒十億,那我兩億跑 1.5s 應該能過吧(
瞄了一眼題解發現確實是,那就放心了。
考慮求最長上升子序列的二分的做法,即維護 \(f_i\) 表示要達到長度為 \(i\) 的上升子序列,序列的最后一個元素最小可以是多少,如果達不到則為 \(\infty\)。每次考慮新元素 \(a\) 的時候將 \(f_x\) 改為 \(a\) 即可,其中 \(x\) 是滿足 \(f_{x} \ge a\) 的最小的 \(x\),可以二分查找求出。
遇到空位的時候,因為是嚴格上升子序列,可以發現不需要考慮重復元素等情況,即可以當作無限制地使用給出的數,最后還原方案時再考慮構造即可。
還原方案時從后往前維護,令當前位置為 \(i\),對於有空位的位置不好考慮(因為有 \(m\) 種取值無法一一考慮),所以考慮枚舉上一個不是空位的位置 \(j\),需要滿足中間的可以填進空位的最多個數恰好為兩個位置 \(i\) 和 \(j\) 的最長上升子序列之差(\(num = len_i - len_j + 1\)),然后按照數值從大到小的順序將 \(num\) 個數填入從后往前的每個空位即可。
最后再隨意填入還沒填入數值的空位就行了。
時間復雜度為 \(\mathcal O (n \log n + m \log m + k(n + m))\),評測鏈接。
2019-11-21
cf671D
以 \(1\) 為根建樹。
如上圖,\(u\) 是非根節點,\(p\) 是 \(u\) 的雙親節點,令 \(f_u\) 表示覆蓋圖上的子樹的最小代價,即覆蓋 \(u\) 和 \(p\) 之間的邊以及 \(u\) 的子樹中的所有邊的代價。
則最終的答案為 \(1\) 的每個孩子的 \(f\) 值之和。
如上圖,這種方法的好處在於:假設考慮使用了紅色線覆蓋了 \(u \leftrightarrow p\) 這條邊,則貢獻為圖中的藍色數值 + 紅色線的代價。
如上圖,考慮一條形如紅色線的覆蓋鏈,即經過 \(u\) 和 \(u\) 的孩子 \(a\) 的鏈,考慮從 \(a\) 繼承轉移信息。
可以發現,假設紅色鏈對 \(f_a\) 的貢獻為 \(v\),則對 \(u\) 的貢獻應該為 \(\displaystyle v + \sum_{\begin{subarray}{c} x \in {son}_u \\ x \ne a \end{subarray}} f_x\),即 \(\displaystyle v + \sum_{x \in {son}_u} f_x - f_a\)。
所以考慮直接從子樹繼承貢獻,但是經過 \(u \leftrightarrow a\) 的紅色線可能不會經過 \(u \leftrightarrow p\),所以維護一個所有轉移的可並堆,堆為按照轉移代價為權值的小根堆,當堆頂不合法時彈出堆頂即可。
可並堆需要維護整體打加減標記(\(\displaystyle v + \sum_{x \in son_u} f_x - f_a\))以及合並,手寫左偏樹實現即可。
時間復雜度為 \(\mathcal O (n + m \log m)\),評測鏈接。
2019-11-22
agc033_d
考慮一個朴素的 DP:\(dp(topleft, bottomright)\) 表示左上角為 \(topleft\),右下角為 \(bottomright\) 時這個矩形區域的權值。
狀態數就是 \(\mathcal O (H^2 W^2)\) 的了,考慮優化狀態。
容易發現權值最大不超過 \(\lceil \log_2 H \rceil + \lceil \log_2 W \rceil\),且在當 \((i + j) \bmod 2 = 0\) 時 \(A_{ij}\) 為.
否則為#
,即黑白染色時取到上限。
那么記 \(f(complexity, top, bottom, left)\) 為滿足 \(dp(topleft, bottomright) \le complexity\) 的最大的 \(right\) 值,如果不存在這樣的 \(right\) 則為 \(left - 1\)。
同理記 \(g(complexity, left, right, top)\) 為滿足 \(dp(topleft, bottomright) \le complexity\) 的最大的 \(bottom\) 值,如果不存在這樣的 \(bottom\) 則為 \(top - 1\)。
這樣子就可以實現轉移,具體方式是:以 \(complexity\) 為階段,每次從上一個階段轉移而來(可以滾動數組)。
先考慮 \(f\) 只算劈成左右兩半的方案的貢獻,\(g\) 只算劈成上下兩半的方案的貢獻,這樣子可以直接以 \(f(top, bottom, left) = f'(top, bottom, f'(top, bottom, left) + 1)\) 的方式進行轉移。\(g\) 同理,最后再固定 \(topleft\),利用雙指針進行合並即可。
時間復雜度為 \(\mathcal O (W H (W + H) \log WH)\),評測鏈接。
2019-11-23
cf605E
假設已經求出了所有點到終點 \(n\) 的距離,則每個點必然會前往距離盡量小的點,列出滿足條件的方程,以 Dijkstra 的方式從終點 \(n\) 往回逆推即可。
時間復雜度為 \(\mathcal O (n^2)\),評測鏈接。
cf585E
令 \(\displaystyle v = \max_{i = 1}^{n} a_i\),以及 \(\displaystyle b_x = \sum_{i = 1}^{n} [a_i = x]\),即 \(b_x\) 為 \(x\) 在 \(a\) 中出現的次數。
利用 \(b\) 數組求出 \(b'\) 數組,滿足 \(b'_x\) 為 \(x\) 的倍數在 \(a\) 中出現的次數。
具體的求法為:枚舉質數 \(p\) 做該維時間復雜度為 \(\displaystyle \mathcal O \!\left( \frac{n}{p} \right)\) 的高維后綴和,即做一個類似 FMT 的變換。
由於 \(\displaystyle \sum_{\begin{subarray}{c} p \in \mathbb{P} \\ p \le n \end{subarray}} \frac{1}{p} = \mathcal O (\log \log n)\),所以這部分的時間復雜度為 \(\mathcal O (v \log \log v)\)。
求出 \(b'\) 后,就可以求出 \(f\) 表示從 \(a\) 中選出一個非空子集滿足 \(\gcd = 1\) 的選擇方案數。
以及 \(g\) 表示從 \(a\) 中選出一個非空子集滿足 \(\gcd = 1\) 的子集大小的和。
即 \(\displaystyle f = \sum_{\gcd(S) = 1} 1\),以及 \(\displaystyle g = \sum_{\gcd(S) = 1} |S|\)。
\(f\) 和 \(g\) 都可以通過簡單的莫比烏斯反演求出。
通過容斥原理不難得出答案即為 \(2g - nf\)。
時間復雜度為 \(\mathcal O (n + v \log \log v)\),評測鏈接。
2019-11-26
cf521E
不難發現答案中的三條路徑必定在同一個點雙中,進一步地,這個點雙中的邊數必須大於點數(不是環)。
也就是說只要原圖不是仙人掌森林就必然能找到方案。
對於一個邊數大於點數的點雙,考慮其中的一個環,這個環上必然有一條“弦”,即一條鏈連接着環上的兩點,則將起點和終點設為這條“弦”的兩端,三條路徑分別為“弦”和環被“弦”分成的兩半即可。具體實現細節詳見代碼。
時間復雜度為 \(\mathcal O (n + m)\),評測鏈接。
2019-11-27
cf521D
對於三種不同的操作,易證:賦值操作最先執行;加法操作其次;乘法操作最后執行。
考慮最終價值是所有技能價值的乘積,所以乘法操作對最終價值產生 \(b_j\) 倍的貢獻,按照 \(b_j\) 從大到小的順序排序。
對於賦值操作,每個技能只要留下最大的那個即可,可以發現此時賦值操作和加法操作可以視作同一種,即把賦值操作的 \(b_j\) 減去 \(a_{i_j}\) 即可,最終如果選取了這個賦值操作就把它提到最前面去,不影響答案。
對於加法操作,顯然同一個技能的加法操作應該先選擇 \(b_j\) 大的。由這個前提不難推出,每次應該選擇 \(\dfrac{b_j}{a_{i_j}}\) 最大的操作執行(\(a_{i_j}\) 是當前的技能價值,而不是初始價值)。按照 \(\dfrac{b_j}{a_{i_j}}\)(\(a_{i_j}\) 對相同的 \(i_j\) 也不一定相同)從大到小排序即可。
假設最終選取了 \(x\) 個加法操作,易證答案以 \(x\) 為自變量的時候是單峰的,只要讓 \(x\) 從 \(0\) 開始增加,直到答案無法增大時停下即可。
時間復雜度為 \(\mathcal O (k + n \log n)\),評測鏈接。
cf547D
構造二分圖,左側的點表示每一行,右側的點表示每一列。第 \(x\) 行表示的點和第 \(y\) 列表示的點之間有連邊當且僅當坐標 \((x, y)\) 在輸入中給出。
和 cf528C 相同的結論,利用邊數為偶數的歐拉回路構造方案。
特別地,這張圖還是二分圖,每一側新建一個虛點,左側的度數為奇數的點和右側的虛點連邊,右側反之。如果最后虛點度數為奇數,則在兩虛點間連一條邊。因為如果一張連通二分圖存在歐拉回路,則其邊數必然為偶數,就不用添加自環了(自環會影響答案合法性)。
構造出邊數為偶數的歐拉回路后,歐拉回路上的邊交替用紅藍兩色染色,可以保證不包含新的邊時,每個點相鄰的邊中的顏色平衡。因為每個實點最多往外連一條邊,所以去掉一條邊后顏色差不超過 \(1\)。
時間復雜度為 \(\mathcal O (n + v)\),其中 \(v\) 為值域,評測鏈接。
2019-11-29
cf582D
令 \(v_p(n)\)(\(p\) 是質數,\(n\) 是正整數)表示 \(n\) 的標准分解式中的 \(p\) 的冪次。
可以發現 \(\displaystyle v_p \!\left( \binom{a + b}{a} \right) = v_p( (a + b)! ) - v_p(a!) - v_p(b!)\)。
將 \(a, b\) 表示為 \(p\) 進制數后,不難發現,在 \(p\) 進制下進行 \(a\) 和 \(b\) 的加法運算時,進位的次數恰好等於 \(\displaystyle v_p \!\left( \binom{a + b}{a} \right)\)。
所以將 \(A\) 轉為 \(p\) 進制數(朴素實現的時間復雜度為 \(\mathcal O (\log A \cdot \log_p A)\))后進行數位 DP 即可。
令 \(f(i, j, 0/1, 0/1)\) 表示當位數從高到低考慮到 \(A\) 的第 \(i\) 位,總共進位了 \(j\) 次,\(a + b\)(小於 / 等於)\(A\) 且(不接受 / 接受)低一位的進位時的 \(a, b\) 的取值方案數。以 \(i\) 作為階段,從大到小進行轉移。則答案為 \(\displaystyle \sum_{j \ge \alpha} f(0, j, 0, 0) + f(0, j, 1, 0)\)。
時間復雜度為 \(\mathcal O \!\left( \log_p A \!\left( \log A + \log_p A \right) \right)\),評測鏈接。
cf585F
把 \(s\) 中的所有長度為 \(\displaystyle \left\lfloor \frac{d}{2} \right\rfloor\) 的子串搞出來建個 AC 自動機,然后數位 DP 一下就做完了。
時間復雜度為 \(\mathcal O (|\boldsymbol{\Sigma}| \cdot |s|d^2)\),評測鏈接。
2019-11-30
cf708E
代碼寫的很亂,講個大概思路:
可以發現上下連通當且僅當相鄰層剩下來的區間有交,那么我們考慮自上而下 DP,狀態就為當前剩下的區間:
令 \(dp(i, l, r)\) 表示考慮前 \(i\) 層,第 \(i\) 層的區間為 \([l, r]\) 時的概率,轉移時枚舉上一層的區間即可。
這個做法狀態數就是 \(\mathcal O (n m^2)\) 的了,不能接受。
考慮區間 \([l, r]\),和它有交的區間 \([l', r']\) 需要滿足 \(r' \ge l\) 且 \(l' \le r\),當然還有 \(l' \le r'\)。
條件比較復雜,容斥一下可以發現也等價於所有區間減去 \(r' < l\) 的區間減去 \(l' > r\) 的區間(前提是滿足 \(l' \le r'\))。
那么現在轉移就方便了,等於上一層的 DP 值的總和減去上述兩個限制條件。
考慮令 \(f(x)\) 表示所有滿足 \(l > x\) 的區間的 DP 值之和,令 \(g(x)\) 表示所有滿足 \(r < x\) 的區間的 DP 值之和。
(由對稱性容易發現 \(g(x) = f(m + 1 - x)\))
這時狀態數仍然是 \(\mathcal O (n m^2)\) 的,考慮直接利用上一層的 \(f\)(或 \(g\))求出這一層的 \(f\)(或 \(g\))。
推一波式子就發現,確實是可以求的,然后按照式子進行計算就行了。
計算時需要預處理形如 \(\displaystyle \binom{k}{i}\) 的組合數。
時間復雜度為 \(\mathcal O (nm + k)\),評測鏈接。
2019-12-02
cf568C
顯然前面的形式是個 2-SAT,建圖、Tarjan 求強連通分量、bitset 求傳遞閉包一氣呵成。
構造方案時直接 DFS,要記一下當前是否已經大於原串(也就是后面的可以任意填),可以證明遞歸到的狀態是 \(\mathcal O (n)\) 的,還要用數組記一下不能選的點,這里也用 bitset 優化,是 \(\mathcal O (n^2)\) 的。
時間復雜度為 \(\displaystyle \mathcal O \!\left( l + n + m + \frac{nm + n^2}{w} \right)\),其中 \(w\) 為字長,評測鏈接。
cf611G
考慮固定對角線的一點 \(x\),對於另一點 \(y\),\(\vec{xy}\) 左側的面積小於等於總面積的一半對應的 \(y\) 是一段區間,雙指針求出區間的分界點后,把公式套上去算就完事了,需要預處理多個前綴和數組,注意控制精度別爆 long long 了。
時間復雜度為 \(\mathcal O (n)\),評測記錄。
2019-12-03
cf582E
答案即這 \(n\) 個方程左側的取值恰好等於右側時的方案數。
上表達式樹后,很難直接獲得信息,所以考慮維護方程左側在 \(2^n\) 種取值中,取到每一種取值的方案數。
即在子樹中,對於每個數 \(0 \le x < 2^n\) 維護滿足方程左側的狀態壓縮后恰好為 \(x\) 的替換 ?
的方案數。
直接在表達式樹上合並信息即可,用 FWT 實現快速信息合並。
時間復雜度為 \(\mathcal O (|s| n 2^n)\),評測記錄。
cf504E
對原樹進行字符串哈希,每個點存根到它的字符串和它到根的字符串的哈希值,就可以 \(\mathcal O (1)\) 提取一條沒有拐點的鏈的哈希值。
把 \(a \to b\),\(c \to d\) 兩段路徑分解為 \(\mathcal O (\log n)\) 條重鏈區間的並。
每次嘗試將 LCP 擴展兩條路徑的當前區間長度的最小值,也就是至少消掉一個區間,這樣最多 \(\mathcal O (\log n)\) 次消完。
如果擴展失敗,在區間上進行二分查找即可,復雜度也是 \(\mathcal O (\log n)\)。
時間復雜度為 \(\mathcal O (n + m \log n)\),評測記錄。
- WA6 原因:哈希的模數選太大了,導致做加減法也要加
(LL)
,但是我沒加。
2019-12-07
agc032_f
丟人,看了 題解 才會,也不知道怎么寫題解。
時間復雜度為 \(\mathcal O (n \log \mathrm{MOD})\),評測鏈接。
2019-12-13
agc027_d
如圖所示,黑白染色后,每個黑色格子按照每個正 / 反斜對角線填上兩個質數的乘積。
令 \(m=1\),則白色格子上的數為相鄰四個黑色格子上的數的 \(\mathrm{lcm} + 1\)。
稍微調整一下質數的順序,就可以做到數不超過 \(10^{15}\) 了。
時間復雜度為 \(\mathcal O (n^2)\),評測鏈接。
2019-12-17
agc032_d
題意為:將一個數往右扔需要花費代價 \(A\),往左扔需要花費代價 \(B\),問排序的最小代價。
令 \(pos_i\) 表示數 \(i\) 現在所在的位置,也就是說將 \(pos_i\) 增加需要 \(A\) 的代價,減少需要 \(B\) 的代價。
那么令 \(dp(i, j)\) 表示考慮前 \(i\) 個數,\(pos_i = j\) 時的最小代價即可。
注意 \(j\) 的取值只需要標記是 \(1, 2, \ldots , n\) 或者是 \((-\infty, 1), (1, 2), (2, 3), \ldots, (n - 1, n), (n, +\infty)\) 即可。
時間復雜度為 \(\mathcal O (n^2)\),評測鏈接。
2019-12-19
agc037_d
把最終應該在同一行中的數染成同一種顏色,即 \(1 \sim m\) 染 \(1\) 號顏色,\((m+1) \sim 2m\) 染 \(2\) 號顏色,以此類推。
可以發現總共有 \(n\) 種顏色,每種顏色恰好有 \(m\) 個數。
第一次變換后的矩陣應當滿足:每一列中的 \(n\) 個位置,恰好包含了所有 \(n\) 種顏色。
考慮從左到右一列列地確定第一次變換后每一列應當有哪些數。
建立二分圖:如果第 \(i\) 行的第 \(j\) 個位置是顏色 \(k\),則左側的 \(i\) 號點向右側的 \(k\) 號點連一條邊。
可以發現只要找到 \(m\) 個完美匹配就行了,一個完美匹配對應着某一列的染色情況。
跑 \(m\) 遍匈牙利算法即可。
時間復雜度為 \(\mathcal O (n^2 m^2)\),評測鏈接。
2019-12-20
arc095_f
考慮以數值從小到大的順序加入 \(p\) 中的元素,可以發現原樹必須是毛毛蟲,然后瞎調整一下就完事了。
時間復雜度為 \(\mathcal O (n)\),評測鏈接。
2019-12-21
arc098_f
解法基於這樣一個重要事實:存在一種最優情況滿足不會回到已經捐款過的節點,因為如果回去了,可以把捐款時間點挪后。
考慮 \(C_i = \max \{ A_i - B_i, 0 \}\),可以發現原題意等價於:捐款后剩余錢數也需要大於等於 \(C_i\)。
轉化后的題意就好考慮了,容易發現對於 \(C_i\) 最大的點 \(u\),因為捐款后不會返回,所以假如刪除 \(u\) 后把整張圖分成了若干個連通分量(假設為 \(k\) 個),需要先處理 \(k-1\) 個連通分量,再在 \(u\) 上捐款,然后移動到最后一個連通分量里進行捐款,並且再也不回到 \(u\)。
容易發現這個結構類似於按照 \(C_i\) 從小到大的順序建一個類 Kruskal 重構樹,以 \(C_i\) 最大的點 \(u\) 為根,其每一個子樹表示 \(k\) 個連通分量中的一個。
令 \(dp(x)\) 表示在 \(x\) 的子樹內捐款最少需要准備多少錢,自底向上轉移即可。
時間復雜度為 \(\mathcal O (n \log n)\),評測鏈接。
2019-12-22
cf639E
通過調整法不難證明,最優策略為按照 \(t_i / p_i\) 升序依次選取,也就是說和 \(c\) 無關。
對於 \(t_i / p_i\) 相同的,任意順序均可,那么我們可以求出某個題的最快解決時間和最慢解決時間(在最大化總得分的條件下)。
令第 \(i\) 題的最快 / 最慢解決時間分別為 \(l_i, r_i\)。
也就是詢問對於任意一組 \(p_i < p_j\),均需要滿足 \(p_i \!\left( 1 - \frac{l_i}{T} \right) < p_j \!\left( 1 - \frac{r_j}{T} \right)\)。
進一步地,可以發現如果 \(p_i < p_j < p_k\),只需檢查 \(i, j\) 和 \(j, k\) 而不需要檢查 \(i, k\)。
所以把所有題目按照 \(p_i\) 升序排序,對於相鄰的 \(p_i\) 相同的塊分別檢查即可。
時間復雜度為 \(\mathcal O (n \log n)\),評測鏈接。
2019-12-23
cf559E
先把所有燈按照 \(a_i\) 遞增排序。
我們考慮最右側被照到的點是哪個燈的,假設是 \(i\) 的,如果 \(i = n\),則可以向左照或者向右,否則當然就是只能向右。
我們先考慮 \(i\) 向右的情況,可以發現 \(i + 1\) 到 \(n\) 這之中的所有燈,最優選擇都是向左,因為向右要么與條件沖突,要么沒有意義。
這之中的所有燈都向左了,可能還會照到其它更左側的燈,同理這些燈的選擇也是向左,然后照到更多的燈,這樣連鎖反應下去最終會停止。通過預處理區間中的 \(a_i - l_i\) 的最小值,我們可以在 \(\mathcal O (n \log n)\) 的時間內(利用 ST 表)求出 \(lb(i)\),表示如果 \(i\) 向左照,最多能影響到多遠,這個坐標必然是某一個燈的 \(a_j - l_j\),我們記下這個編號 \(j\) 即可。
然后考慮這樣下去停下了,假設 \(j\) 以及 \(j\) 右側的所有燈(除了 \(i\))都向左照了,我們可以處理出被照亮的區間的最左端點,這個端點要么是某個燈的 \(a - l\),要么是 \(a_i\) 本身。
然后考慮處理更左側的段即可,此時我們發現多了個右側的左端點的限制,如果照亮的部分超過了右邊區間的左端點則不算,這個其實區別不大,只要算照亮右邊區間左端點左側的貢獻即可。
還有一個情況是 \(n\) 本身就向左照了,經過上面的分析,發現這個情況其實更簡單,只要用 \(lb(n)\) 直接轉移就行了。
所以這是一個有 \(n\) 個狀態(因為每次右側區間的左端點只有可能是 \(a_i\) 或者 \(a_i - l_i\)),每個狀態從 \(n\) 個狀態轉移,每次轉移代價為常數的動態規划。
時間復雜度為 \(\mathcal O (n^2)\),評測鏈接。
2019-12-24
cf576E
加刪邊,問是否是二分圖 —— 線段樹分治,帶權並查集。
一個線段樹分治的技巧:可以任意修改在當前時間點之后的加入操作,即當前時間點為 \(i\) 時,可以任意修改滿足 \(i \le l \le r \le q\) 的操作 \([l, r]\)。
線段樹分治 + 帶權並查集板子題。
時間復雜度為 \(\mathcal O (nk + m \log m + q \log n \log m)\),評測鏈接。
2019-12-25
cf578E
也就是把 \(s\) 分成最少數量的子序列,滿足每個子序列都是 LR 交替的,而且它們按照某種順序拼接起來也是 LR 交替的。
先嘗試拋開第二個條件,求出最少的子序列個數,滿足每個子序列都是 LR 交替的。
可以證明「每次增加一個字符,如果之前有結尾為相反字符的子序列的話,接在后面,否則自成一個新的子序列」的貪心是正確的。
考慮分別有若干(可能是 \(0\))條開頭和結尾分別是 LL,LR,RL,RR 的子序列,如何將它們拼成拼接位置也是 LR 交替的子序列。
如果既有 LR,也有 RL,考慮把所有 LR 拼起來,所有 RL 也一樣,但是它們並不能直接相連。
考慮哪一個的最后一個字符的位置更靠后,把這個字符接在另一個序列的后面即可。
這樣子能構造出僅剩一條 LR 或者 RL。
再考慮 LL 和 RR,因為只有最多一條 LR 或者 RL,肯定有辦法直接拼上,分類討論即可。
時間復雜度為 \(\mathcal O (|s|)\),評測鏈接。
2020-01-06
cf526F
不知道哪里來的原題,有多種做法:
-
單調棧 + 線段樹:掃描線,固定右端點,右端點往右掃,維護一個區間中的左端點形成的區間 \([l, r]\) 的 \((max - min) - (r - l + 1)\) 的最小值個數。
-
線段樹:掃描線,從值域的角度考慮,固定最大值,從小往大掃,維護一個區間中的最小值形成的位置集合的連續段數量的最小值個數,我寫的是這種做法。
-
題解的做法是分治,把序列從正中間划分成兩半,先遞歸處理兩半,然后分四種情況討論跨過中點的部分。
時間復雜度為 \(\mathcal O (n \log n)\),評測鏈接。
2019-01-08
cf571D
根據 U, M 操作建出兩個 Kruskal 重構樹(類似物),然后對於每個 A, Z 操作在對應節點上掛鏈。
一次 DFS 求出每個 Q 操作對應的上次襲擊時刻,再一次 DFS 求出答案,都使用樹狀數組維護。
題解用的是帶權並查集,不失為一種好方法。
時間復雜度為 \(\mathcal O (n + m \log m)\),評測鏈接。
cf575I
轉成五種不同的偏序的疊加,二維樹狀數組維護。
時間復雜度為 \(\mathcal O (N^2 + Q \log^2 N)\),評測鏈接。
2019-01-10
arc100_f
稱滿足題目條件的序列是合法的,則答案為任意序列出現 \(A\) 的次數減去不合法序列出現 \(A\) 的次數。
其中,任意序列出現 \(A\) 的次數即為 \((N - M + 1) K^{N - M}\)(先枚舉位置,再枚舉剩下的字符)。
考慮統計不合法序列出現 \(A\) 的次數,這里分三類討論:
-
\(A\) 就是合法的,則包含 \(A\) 的序列都是合法的,所以總數為 \(0\)。
-
\(A\) 中存在相同的字符,這意味着連續 \(K\) 個不同字符的連續段,只可能出現在 \(A\) 的左側或右側,不可能覆蓋 \(A\)。也就是說 \(A\) 的左右兩側是獨立的,可以枚舉 \(A\) 出現的位置,然后算出左右兩側的方案數相乘再相加。對左右兩側分別進行 DP,求出往 \(A\) 的左側或右側添加若干個字符,且得到的序列不合法的方案數。最后相乘再相加即可。
-
\(A\) 不是合法的,但是不存在相同字符,這時必然有 \(M < K\)。使用類似上例中的 DP 方式,統計出所有不合法序列中,連續 \(M\) 個不同字符的連續段個數。可以發現每個這樣的連續段,有恰好 \(\dfrac{(K - M)!}{K!}\) 的概率等於 \(A\)(考慮字符可以任意排列,方案數為 \(K!\),但是恰好排列出 \(A\) 的方案數只有 \((K - M)!\))。所以連續段個數除以 \(A_K^M\)(排列數)就是要求的總數。
把 \((N - M + 1) K^{N - M}\) 減去不合法序列出現 \(A\) 的次數就是答案。DP(加前綴和優化)的復雜度即為 \(\mathcal O (NK)\)。
時間復雜度為 \(\mathcal O (NK)\),評測鏈接。
cf704D
先離散化,然后套路地轉二分圖網絡流模型。
如果一個點染紅色(假設 \(r < b\),如果不是的話就紅藍反過來),那條邊的流量就為 \(1\),否則為 \(0\)。
那么就是要求最大流,然后發現每行每列限制其實就是個上下界,套有源匯有上下界最大流板子即可。
點數邊數都是 \(\mathcal O (n)\) 的,使用 Dinic 實現,因為二分圖中間層是單位容量,所以復雜度為 \(\mathcal O (n \sqrt{n})\)。
時間復雜度為 \(\mathcal O (m \log n + n \sqrt{n})\),評測鏈接。
agc032_c
題目告訴我們這張圖是個連通圖,那么首先要有歐拉回路,否則無解。
如果存在度數 \(\ge 6\) 的點,從它開始的歐拉回路就會三次回到它本身,必然有解。
如果沒有度數為 \(4\) 的點,只有度數為 \(2\) 的點,那就是說這張圖是一個環,不可能有解。
現在只剩至少一個度數為 \(4\) 的點和度數為 \(2\) 的點,我們把度數為 \(2\) 的點縮掉:
留下來的圖就只會有度數為 \(4\) 的點,並且可能存在重邊和自環。
如果只有一個度數為 \(4\) 的點,那必然是它連了 \(2\) 條自環,無解。
如果只有兩個度數為 \(4\) 的點,那么就有兩種情況:
-
兩點之間有 \(2\) 條邊,每個點有 \(1\) 個自環:有解。
-
兩點之間有 \(4\) 條邊:無解。
如果存在 \(\ge 3\) 個度數為 \(4\) 的點,考慮從某個點出發的歐拉回路,它必然會回到這個點兩次,
在這兩個圈中,如果存在一個點在其中一個圈中出現了兩次,就能分離出另一個圈;
否則必然存在兩個點,分別出現在兩個圈中,拆下來也可以分別組成三個圈。
所以只要判斷只有兩個度數為 \(4\) 的點的情況,是上面的哪一種即可。隨便寫個遍歷就能判斷了。
時間復雜度為 \(\mathcal O (N + M)\),評測鏈接。
2020-01-14
arc089_f
\(N \le 70\) 的數據范圍不懷好意,果然是一個神題。
首先可以觀察到,對於最終形成的序列,取出其中一個極大有顏色連續段,可以發現最短的染色序列有如下規律:
(這里把相同的連續多個字符縮成一個字符,顯然對結論沒有影響)
-
r
:最短染色序列為r
。 -
b
或rb
或br
或rbr
:最短染色序列為rb
。 -
brb
或rbrb
或brbr
或rbrbr
:最短染色序列為rb?
(?
表示可以填任何字符)。 -
brbrb
或rbrbrb
或brbrbr
或rbrbrbr
:最短染色序列為rb??
。
以此類推。
不難發現,只要染色序列包含了最短染色序列為子序列,那么也一定可以染成最終的模樣,而不包含則一定不行。
我們把這些序列依次編號,有 \(x\) 個 b
的編號為 \(x + 1\)(和上面的編號相同)。
那么某個最終狀態就可以被表示為一個序列,比如 wwbbrbrbrrrwwrrwwrbwbbb
就可以被表示為 \(\{4, 1, 2, 2\}\)。
也就意味着,如果 \(s\) 含有 rb??
、r
、rb
、rb
作為不相交子序列,就可以得到這個最終狀態。
如何判斷是否包含呢?容易想到一個貪心的做法:按照編號從大到小排序,先按順序把 r
安排上,再把 b
安排上,最后安排剩下的 ?
,正確性用調整法不難證明。
但是這又有什么用呢,不是要計數嗎?
可以發現只要兩個最終狀態被表示成的序列(排序后)相同,那么這兩個最終狀態就是等價的。所以只要枚舉對應的序列就行。
這個最終狀態對應的序列方案數其實類似於整數分拆,因為那些編號的和不能太大,而且是無序的。
假設 \(N = x\) 時可行的序列方案數為 \(f(x)\),則有 \(f(x) \le x \mathrm{Partition}(\lfloor x / 2 \rfloor)\)。
實際上,當 \(N = 70\) 時,\(f(N)\) 也只有 \(418662\)。
那么有了序列,如何計算有多少個最終狀態對應到這個序列呢?
實際上就是一個多重組合數(序列的重排方案數)乘以用隔板法計算的填充方案數(也就是 brbwbwr
變成 wwrrbrrbwrbbrwwrrw
,有 \(13\) 個地方可以插入新字符,有 \(11\) 個新字符可供插入,所以乘上一個 \(\binom{11 + 13 - 1}{13 - 1}\))。
具體細節詳見代碼。
時間復雜度為 \(\mathcal O (K + N f(N))\),評測鏈接。
agc039_d
如圖所示,單位圓上的三點組成 \(\triangle ABC\),內心為 \(I\),令 \(A', B', C'\) 分別為弧 \(BC, AC, AB\)(不經過 \(A, B, C\) 的那一段)的中點。
則由雞爪定理和同一法可知,\(AIA'\),\(BIB'\),\(CIC'\) 均三點共線;
且 \(B'I = B'C\),\(A'I = A'C\),所以 \(IC \perp A'B'\),所以 \(C'I \perp A'B'\)。
同理可得 \(A'I \perp B'C'\),\(B'I \perp A'C'\),即 \(I\) 同時為 \(\triangle A'B'C'\) 的垂心 \(H'\)。
由歐拉線定理可得,\(\overrightarrow{OH'} = 3 \overrightarrow{OG'} = \overrightarrow{OA'} + \overrightarrow{OB'} + \overrightarrow{OC'}\)。
所以要求 \(E(I) = E(H')\) 只要求 \(E(A') + E(B') + E(C')\) 即可。
枚舉點對計算就可以了。
時間復雜度為 \(\mathcal O (N^2)\),評測鏈接。
2020-01-15
cf639F
也就是,給定一張無向圖,每次詢問在原圖的基礎上加一些邊,然后問一些點是否在同一個邊雙連通分量中。
眾所周知,一張圖將邊雙連通分量縮點后構成一個森林,先把原圖的這個森林建出來(用 Tarjan)。
然后將新加的邊的端點和詢問的點作為關鍵點,建虛樹(代碼中用了樹剖求 LCA),然后加邊跑 Tarjan 即可。
時間復雜度為 \(\mathcal O (n + m + \sum (n_i + m_i) \log (n_i + m_i))\),評測鏈接。