「題集」精致的袖珍題目


「NOIP2008 提高組」雙棧排序

題目鏈接:洛谷


考慮兩個位置不能被放入同一個棧中的條件。

通過多次手玩可以發現,如果有 \(i<j<k,a_k<a_i<a_j\),則 \(i,j\) 不能被放入同一個棧中。

\(a_i<a_j\) 要求 \(i\) 先於 \(j\) 出棧,但是 \(i\) 想要出棧就必須要 \(j\) 入棧,所以 \(j\) 要先於 \(i\) 出棧,因此矛盾。


一定要注意這個 \(k\) 的存在,才能保證 \(j\) 必須要進棧。

現在我們有兩個棧,這就說明我們需要將所有位置分到兩個集合當中,滿足每個集合中元素兩兩不沖突。分集合可以看作對點染色,而染色的要求就是,對於任意一對沖突的 \((i,j)\)\(i,j\) 顏色不同。不難發現這是將所有的 \((i,j)\) 當作邊加入圖中后,對圖進行黑白染色,模擬操作即可。如果不存在染色方案,那么就應該輸出 0。

假如我們知道了染色方案,我們可以貪心地構造出操作序列——只需要每一輪貪心地選取字典序最小的合法操作即可。操作序列中 a 的位置由染色方案限制,因此我們需要盡量讓較小的位置可以被放入第一個棧中,貪心地染色即可。

小結:

  1. 對於重要結論,一定保證正確,不能缺漏或者不完整。一定要用多種數據來檢查,最好可以給出嚴謹的說明/推導!
  2. 注意將問題轉化到圖上這種研究方式,直觀清晰;轉化看對象的角度常常是有效的。

「CF1064D/CF1063B」Labyrinth

題目鏈接:CF洛谷


\((x_0,y_0)\) 出發到達 \((x_1,y_1)\) 的時候,可以發現向左/向右的次數必然滿足一條等式關系:

\[x_1-x_0=R-L \]

那么只需要最小化其中一個量即可。

小結:

注意隱含條件:如果遇到多個變量的問題不方便轉化,不妨入手看看特定情況下(某些信息枚舉/推算之后)有沒有變量之間的關系

「CF877D」Olya and Energy Drinks

題目鏈接:CF洛谷


每個位置在行和在列上可以到達的位置是一段區間,因此我們可以使用 set 維護每一行、每一列上未被遍歷的位置

小結:這里利用了 BFS 的特性(每個點只需要被遍歷到一次),同時也利用了圖的特性。注意使用數據結構維護有效點的方法

使用線段樹優化建圖 +0/1BFS 應該也有正確的復雜度,不知道為啥過不了。

「CodeChef20May」雙色城

題目鏈接:Vjudge


容易發現兩行之間的轉移可以用矩陣來描述,那么我們需要維護的是從第一行到最后一行的矩陣的乘法(或者也可以看作是 DP 數組)。

矩陣的乘法的性質就是“可加而難減,具有結合律”,此處我們可以雙棧模擬隊列規避矩陣求逆,可以做到 \(O(qn^2)\)

小結:注意雙棧模擬隊列的技巧,它可以用來維護隊列中具有結合律、容易加而不易減的信息,例如 \(\min,\max\) 和矩陣乘法。

「CF23C」Oranges and Apples

題目鏈接:洛谷


如果我們只考慮其中一種水果滿足要求,那么排序之后取前 \(n\) 大的即可。

現在需要兩種水果都滿足要求,那么容易想到一種方向:由於一共有 \(2n-1\) 個盒子,取出一個之后,剩下的正好可以分出 \(n-1\) 組,每組里面有兩個;我們可以從每組中選取一個,加上最初取出來的那一個,得到了一種方案;

結合前面的想法,我們可以將盒子按照蘋果排序,有最多蘋果的盒子單獨取出來,剩下的相鄰兩個盒子分在一組。而后,每組中我們選取橘子數目較多的那一個。這樣優先保證組內選取時蘋果的差距較小,而后最大化橘子數目。

考慮證明這種選法的正確性:

設排序后,第 \(i\) 個盒子內蘋果數量為 \(a_i\),橘子數量為 \(o_i\);我們的分組方案會將 \(i\)\(i+1\) 分為一組,其中 \(i=2k,1\le k<n\)

根據條件,同一組內 \(a_i\le a_{i+1}\);所以考慮 \(a\) 最小的選取方案,我們會選擇奇數位的盒子,此時一一跨組對應有 \(a_i\ge a_{i-1},i=2k+1\),同時 \(a_1\ge 0\),所以一定有 \(\sum_{k=0}^{n-1}a_{2k+1}\ge\sum_{k=1}^{n-1}a_{2k}\),因此蘋果數保證不少於一半。

考慮橘子,同一組內,選取的 \(o\) 一定不會小於同一組內另外一個,類似地得出橘子數也保證不少於一半。

小結:注意題設條件的一些細節,比如\(2n-1\) 中選出 \(n\) 個,恰好比一半多 1,比如最終兩種元素的和都保證不少於一半,這些信息都提示我們要考慮一一對應、考慮按照 2 的大小來分組;組合數學的基本方法要掌握!

「CodeChef18Feb」Points Inside A Polygon

題目鏈接:Vjudge


注意到凸多邊形的一個性質,任意兩點的連線都包含在多邊形內部。所以我們可以嘗試在頂點的連線上尋找格點。

一種巧妙的構造方法是,我們嘗試選取凸多邊形上的中點;中點在格點上的條件為起點終點在 \(x,y\) 兩維上坐標同奇偶。根據這個信息我們可以划分 4 個抽屜,每個點必然屬於其中一個抽屜,因此必然有一個抽屜中有 \(\lceil\frac{n}{4}\rceil\) 個點。這樣可以構造出不少於 \(\frac{n^2}{16}\) 個點(需要判重),基本上是足夠了。

小結:注意抽屜原理的運用

一段數學推導

求解下面這個式子的結果:

\[\sum_{j=0}^{n}\binom{j}{k}\binom{n-j}{m-k} \]

滿足 \(n\ge m\ge k\ge 0\)


注意到上指標變動,這種形式出現在 \(\frac{1}{(1-x)^p},p\ge 0\) 的系數中,因此我們可以通過生成函數推導:

\[\binom{j}{k}=\frac{x^k}{(1-x)^{k+1}}[x^j]\\ \binom{n-j}{m-k}=\frac{x^{m-k}}{(1-x)^{m-k+1}}[x^{n-j}]\\ \sum_{j=0}^n\binom{j}{k}\binom{n-j}{m-k}=[x^n]\frac{x^m}{(1-x)^{m+2}}=\binom{n+1}{m+1} \]

小結:下指標變動求和我們可以嘗試范德蒙德卷積,上指標變動我們就應該嘗試生成函數了!對這樣的基礎結構應該要熟悉!

「LibreOJ β Round」ZQC 的手辦

題目鏈接:LOJ


考慮一個暴力的做法:每次取出區間內的最小值,判斷是否符合要求;如果符合要求就刪除它,不符合要求就判斷數量是否足夠;最后我們需要將所有操作撤銷,也就是將所有刪除了的數加回去。

這些操作都可以用線段樹方便地完成,刪除即賦 \(+\infty\),撤銷只需要記錄哪些被刪除了;由於我們只會取出最小值,因此我們只需要針對最小值打標記——記錄區間內的最小值變成了什么。

另一種更巧妙的做法是,原先詢問區間為 \([l,r]\),取出位於 \(p\) 的最小值之后,區間由於不能再包含 \(p\),就相當於分裂成了 \([l,p)\)\((p,r]\);因此我們可以用堆維護當前所有有效區間,每次取出區間最小值最小的區間,操作完后繼續拆分即可。這樣每次最多增加一個區間,可以保證復雜度。

小結:

  1. 查詢前 \(k\) 小的通用方法:取 \(k\) 次最小值;
  2. 注意將集合的減法變成加法的操作,對於易於合並而難以刪除的信息有效;該方法在「NOI2010」超級鋼琴中也有使用。

「CF867E」Buy Low Sell High

題目鏈接:CF


考慮一個比較顯然的錯誤做法:每天都嘗試賣股票,同時在此之前需要有一天來買好股票,所以我們用一個堆維護價值最低且尚未被買入的一天來買入(如果那一天也在賣股票,一買一賣相當於休息一天);如果發現當天賣倒貼錢,就不賣了。

但是這個做法有誤,考慮如下數據:

4
1 2 4 5

該算法會給出“第一天買入第四天賣出”的方案,而最優的方案是“第一第二天買入,第三第四天賣出”。

問題在於,如果某一天的股票被作為中間量抵消了,那么它可以被再次入手。因此我們可以將同一天的價格入堆兩次,第一次表示換股票,第二次表示買股票。

小結:

  1. 貪心算法往往是在試錯中成功,因此不要怕想出錯算法,找出錯才能修正!
  2. 重復入堆的想法比較巧妙,能否借鑒?

「APIO2007」數據備份

題目鏈接:洛谷


最優方案中一定是相鄰的兩個辦公樓配對,因此可以設 \(d_i\)\(i\)\(i+1\) 之間的距離。由於辦公樓不能被多次配對,問題相當於變成了求 \(d\) 中不相鄰 \(k\) 個數的最小和。

考慮一個貪心:每次選出最小的 \(d\),並刪除相鄰的。顯然這個貪心是錯誤的,樣例都過不了。但是考慮,出錯的原因是方案並不完全可以增量構造。如果 \(d_k\) 在方案中,我們同樣可以選擇刪除 \(d_k\) 而加入 \(d_{k-1}\)\(d_{k+1}\)。相似地,如果用 x 表示選中,o 表示不選中,我們可以將方案由 oooxoxoxoxoo 變為 ooxoxoxoxoxo,這樣“取反”可以增大選擇個數,同時保證不相鄰。

因此加入反悔選項,用一個堆來維護當前的最小增量的選項;此外需要用鏈表來維護尚未被確定的點。實現有許多巧妙的地方,比如我們可以直接訪問一個連續段的中心來處理兩個反悔選項合並的情況。建議閱讀代碼。

小結:貪心過程中如果出現了某些方案被忽略的情況,同時容易被快速構造出來,就可以嘗試反悔

「ABC131F」Must Be Rectangular!

題目鏈接:AT


我覺得暴力 bitset 什么的很有機會

一種經典的轉化方式:按照行、列建成二分圖,點 \((a,b)\) 就相當於在行 \(a\) 與列 \(b\) 之間連邊。

考慮題目中給定的操作,就相當於:當左部的某個子集和右部的某個子集已經連通時,就將這個子圖補成完全二分圖:

ABC131F.png

計算每個連通二分圖內部的左部、右部點數即可,並查集/DFS 什么的都可以解決。

小結:注意一下將點看作連邊構建二分圖的方式,比較巧妙(和常見);同時轉化條件要足夠簡潔。

「PMOI-4」可憐的團主

題目鏈接:洛谷


比較簡單的二選一構造題。考慮樹的情況,由於路徑覆蓋限制很松(只要求每個點被覆蓋到一次以上、路徑無環且不同),並且葉子一定要被覆蓋到,樹上的最少路徑數量一定是 \(\lceil\frac{\text{葉子數量}}{2}\rceil\)。這一步構造非常經典,此處略去不講了。

\(l\) 為葉子數量,首先我們應該關注獨立集,如果 \(l\ge \lfloor\frac n 3\rfloor\),葉子已經構成了所需的獨立集;反之,\(l<\lfloor\frac n 3\rfloor\),那么一定有 \(\lceil\frac l 2\rceil\le \lceil\frac n 6\rceil\)

嘗試拓展到一般的簡單連通無向圖,我們可以構建 DFS 樹,這樣可以保證非樹邊均為返祖邊,那么 DFS 樹的葉子之間也就不會連邊。需要注意,雖然根有可能度數也為 1,但是我們不能保證根和其它葉子沒有邊連接,所以我們考慮葉子的時候總不加入根;而構造路徑的時候,度為 1 的根則會影響結果,所以我們可以考慮路徑的時候總加入根

小結:

  1. 樹上的問題大多可以從特殊點入手,包括但不限於根、重心,葉子......
  2. 一定要注意,拓展問題的時候要盡量考慮簡單的修改,而不要快速地加入太多繁雜的修正,這樣既容易攪亂思路,也容易掉入怪圈。思維保有簡潔的連貫性

「ABC216G」01Sequence

題目鏈接:AT


容易看出是差分約束,\(s_i\) 為前綴 \([1,i]\) 的和,考慮每一條約束條件

\[\begin{cases} s_{i+1}\ge s_i,i\in [0,n)\\ s_i+1\ge s_{i+1},i\in [0,n)\\ s_{R_k}-X_k\ge s_{L_k-1},k\in [1,m] \end{cases} \]

建圖的時候,會有源點向每個點連接權為 0 的邊。不過由於 \(s_{i+1}\ge s_i\) 的限制,從 \(s_n\) 開始跑最短路效果一樣。

注意到,如果去掉 \(s_i+1\ge s_{i+1}\),原圖是 DAG。而由於圖上不存在負環,對於一條由 \(s_{R_k}-X_k\ge s_{L_k-1}\) 構造出來的邊,它不會影響到 \(R_k\) 及編號更大的點。因此,我們可以按照原順序算 \(s\),但是需要動態地處理 \(s_i\) 對於標號大於 \(i\) 的點的貢獻,使用樹狀數組就可以了。

小結:

  1. 差分約束系統學得不好啊,最開始一直沒想到 \(s_{i+1}\ge s_i\) 形態的限制,然后又沒有想起來“源點向每個點連一條 0 邊”的操作,卡了半天其實是連圖都不知道怎么建!
  2. 注意一下對於這樣的特殊圖計算最短路的方法,這里主要的想法是“維護某一類邊的貢獻、剩下的當作最短路來算”。

「ARC084B」Small Multiple

題目鏈接:AT


枚舉 \(K\) 的倍數是困難的,但是枚舉一個數本身是簡單的。我們可以通過某種方式枚舉數,並且記錄 \(\bmod K=0\) 的數的最小數碼和。

十進制的正數有一種簡單的枚舉方式:從 1 開始,每次取出一個已經被遍歷、還沒有被擴展的數,而后可以將它 \(\times 10\);如果它末尾小於 9,也可以將它 \(+1\),將兩種情況的結果都放入已有的數集里面。可以發現,這樣每個數會且僅會被枚舉一次。

同時,這種枚舉方法很容易計算數碼和:將 \(+1\) 的權設為 1,將 \(\times 10\) 的權設為 0。我們不需要關心某個數的末尾值,因為如果 \(+1\) 使得個位“超過” 10,那么這樣肯定不會優於 \(\times 10+1\)。所以,從 1 出發到每個數的最短路就是那個數的數碼和。

小結:

  1. 放寬限制,枚舉 \(K\) 的倍數就是枚舉所有數,再考慮 \(\bmod K=0\) 的結果;
  2. 注意這種巧妙的枚舉數的方式,這是從遞歸的角度來構造整數集的。

「CF1473E」Minimum Path

題目鏈接:CF


注意到 \(\max\)\(\min\) 本身所帶的“極值”屬性:假如我們可以任選路徑上的一條邊去除代價,那么選取 \(\max\) 一定是最優的;如果必須任選路徑上的一條邊加上代價,那么選取 \(\min\) 一定是最優的。

因此,我們可以放寬問題的范圍,只需要算那些“選了一條邊刪”和“選了一條邊重復”的最短路即可。

小結:放縮問題而保持最值不變,這是非常常見的處理技巧。需要注意的是,一般而言放縮的東西就和最值有關,而這個最值應該是和最終所求的最值是同向的。

「CF741C」Arpa’s overnight party and Mehrdad’s silent entering

題目鏈接:CF


要求“任意相鄰三個人的食物不同”其實就是說某個人左邊和右邊中一定有一個和他食物不同

在不考慮男女朋友限制的情況下,我們可以分配 \(2k-1,2k\) 的食物不同。想象成二染色問題,我們可以建立圖。

現在再考慮關系限制:這其實就是要在每一對男女朋友之間額外連一條邊。注意到,新圖不可能存在奇環,因此二染色之后即可得到答案。

考慮第一種邊為 A 邊,第二種邊為 B 邊。

這兩種邊都有特性:單獨考慮 A 邊或者 B 邊,它們一定構成了一組匹配

所以原圖如果有環,那么 A 邊后面一定是一條 B 邊,B 邊后面一定是一條 A 邊。這樣配對,則一定只有偶數條邊。

小結:最開始的某些人為的限制(比如要求 \(2k-1\)\(2k\) 食物不同),可以幫助簡化問題。

「UVA1397」The Teacher's Side of Math

題目鏈接:洛谷


沒什么可說的,二項式定理展開對應項的系數即可。

需要注意的是,因為題設條件保證最終可以解出來整數的多項式,因此直接拿 double 消元就可以了,可以避免不少討論。

「ARC127C」Binary String

題目鏈接:AT


注意到,暴力退位的復雜度最終會是 \(O(N)\) 的,因為每當第 \(k\) 位被退了之后,低 \(k\) 位全部變成了 1,這樣下一次碰到第 \(k\) 位退位至少是 \(2^k\) 步之后了。這樣總復雜度為:

\[\sum_{k\ge 0}\lfloor\frac n {2^k}\rfloor=O(n) \]

相似地,有一個結論是,在二進制下,如果從 0 開始,按筆算方式一步一步 +1 直到 \(n\),那么總的進位次數也是 \(O(n)\) 的。

某個經典問題

給定一張二分圖,左側有 \(n\) 個結點,右側有 \(m\) 個結點,共有 \(k\) 條邊。現將圖上的每條邊染成 \([1,c]\) 中的某種顏色,染色后,一個點的代價為與它相連的邊中出現最多的顏色數和出現最少的顏色數之差。找出一種方案,使得代價之和最小。


首先可以分析問題的下界:如果一個點的度數為 \(c\) 的倍數,那么最優情況下它不會貢獻代價;否則,它至少要貢獻 1 的代價。那么就不難算出一個下界為:

\[\sum_u [d_u\bmod c\not =0] \]

然后通過暴力驗證發現這多半就是答案。我們可以嘗試構造出一組合法的方案。

一種構造方法是,我們可以想到,將一個點的任意 \(c\) 條顏色不同的邊打包看成一組,並且拆分成一個新的點。這樣一個點就被分成了 \(\lfloor\frac d c\rfloor\) 個度為 \(c\) 的點和一個度數 \(d\bmod c\) 的點。按照我們的要求,現在任何一個點的鄰邊顏色不同,這就是邊染色的問題。根據 Vizing 定理,二分圖的最大度數為 \(c\),因此這個邊染色是可以做到的。

小結:體會一下分組思想,了解一下 Vizing 定理

「模擬賽」doge digger

有一條狗狗在地上挖洞。考慮一個豎直切面,我們將它看作一個 \(H\times W\) 的矩陣,矩陣的第一行最靠近地面,行數越大就越遠離地面。在豎直切面上,狗狗爪子可以看作一個大小為 \(1\times K\) 的矩形。每次挖洞時,狗狗會選擇一段長度為 \(K\) 的區間,從第一行開始一直向下伸爪子,直到這個區間內出現了泥塊。此時這個區間內的所有泥塊都會立刻消失,並且爪子也會立刻收回。

在旁邊觀看的你想知道,如果狗狗將區間 \([L,R]\) 內行數 \(\le D\) 的泥塊全部挖掉,最少需要伸幾次爪子?你有 \(Q\) 個問題,每個問題之間不會造成影響。

對於 \(100\%\) 的數據,滿足 \(1\le D\le H\le 12;1\le K\le Q,W\le 10^5;1\le L\le R\le W;R-L+1\ge K\)


容易發現行與行之間互不影響。此時問題就變成了一行上,將一段區間內的泥塊全部清理干凈的最小伸爪子次數。

考慮這樣一個貪心:每次找到左端點右側的第一個泥塊,將爪子的最左端對准它清理一次(如果右端超出區間就調整);直到泥塊被清理干凈。可以發現這樣清理一定是最優的,暴力模擬即可得到一個 \(O(QHW)\) 的算法。

注意到,我們關心的始終是區間內的第一個泥塊,因此我們可以始終將左端點指向第一個泥塊,那么當區間為空我們也就清理完了。這個過程可以使用倍增維護,優化即得到了 \(O(QH\log W)\) 的算法。

小結:最基礎的貪心都沒有想到?基礎的思路必須要有!

「模擬賽」Shortest Path

給定質數 \(P\)。設 \(d_{x,y}\) 表示:從 \(x\) 出發,每次可以轉移到 \(x\times z\bmod P,1\le z<P\),代價為 \(|x-z|\),這樣轉移到 \(y\) 的最小代價之和。

對於所有的 \(1\le x,y<P\),求出 \(d_{x,y}\)

對於 \(100\%\) 的數據,滿足 \(1\le P\le 2000\)


顯然是一個最短路的問題。直接暴力無論如何都是 \(O(P^3)\) 的。

注意到一個性質:在數據范圍內,\(d\) 其實很小。這意味着,如果 \(D=\max d\),那么有效的邊數量為 \(O(PD)\)。如果此時再運行 Dijkstra,我們可以得到 \(O(P^2D\log P)\) 的算法。

考慮到有效的邊的邊權比較小,這也就意味着當我們按順序取出距離最小的點的時候,之后可以取出的點的可能距離只有 \(O(D)\) 種。因此,我們可以維護 \(D\) 個隊列來分別維護這些點,復雜度為 \(O(P^2D)\)

小結:注意本題中,最短路徑長度較小和邊權較小兩種情況的處理方式

「模擬賽」Matrix

給定一個 \(n\times m\) 的矩陣 \(A\),求其中任意大小的包含恰好 \(k\) 個不同元素方陣的數量。

對於 \(100\%\) 的數據,滿足 \(1\le n,m\le 1.5\times 10^3,1\le k\le nm,1\le A_{ij}\le 100\)


重要觀察:\(A\) 的范圍很窄,所以可以直接拿 bitset 維護!!!

將“恰好 \(k\) 個不同”變成“至多 \(k\) 個不同”之后就可以二分每個左上角的最大長度。取出一個方陣的元素集合可以使用二維 ST 表

小結:要會用 bitset!一般維護集合的交、並、補,並且元素較少的時候都會用 bitset;另外,關注一下二維 ST 表這個東西。

「CF1326E」Bombs

題目鏈接:洛谷CF


思考過程中有兩點需要注意:

  1. 處理問題需要多方面入手。為什么必須“從前往后”而不能想到“從后往前”呢?思維不要局限了;
  2. 適當地轉化為常見的模型。本題中可以轉化到括號匹配的模型上,更加易於思考。

關於 BFS 的優化

在邊數遠遠大於點數的時候,我們可以通過避免重復訪問的方法來降低復雜度。

例如,當我們需要求兩兩最短路時,直接 BFS 復雜度為 \(O(nm)\)。但是,當圖比較稠密的時候,很有可能幾步搜索后每個點就已經被更新好了,如果再根據邊來搜索點就非常低效。一種有效的處理方法是,使用 bitset 維護好鄰接未遍歷點集,這樣可以保證每一步拓廣都是有效的,復雜度可以降到 \(O(\frac{n^3}{\omega}+m)\)

話說,模擬賽的這道題目數據太水,直接用鏈表維護也過了。

「CF53E」Dead Ends

題目鏈接:CF洛谷


着重講一下如何去重。

仔細分析可以發現,重復計算是因為從同一個點擴展時的邊會出現定序的問題。如果不加限制,那么就會因為順序不同而算重。顯然的去重方法就是轉移的時候欽定順序

假如我們確定了根,那么構造的過程可以看作按照 BFS 順序生成這棵樹。一種方法是,我們總保證加入的葉子是加入后葉子集合中最大的,那么這我也不知道怎么就可以保證每棵樹只被計算一次。

「模擬賽20211104」CONtinuously disCRETE

維護 \(n\) 個棧,編號為 \(1\sim n\),進行如下操作共 \(q\) 次:

  • 操作 1 l r h,對於編號在區間 \([l,r]\) 中的棧,向棧中推入 \(h\) 個編號為當前操作編號的元素;
  • 操作 2 x y,詢問編號為 \(x\) 的棧,從棧底開始第 \(y\) 個元素的編號。如果沒有請輸出 0

對於 \(100\%\) 的數據,滿足 \(1\le n,q\le 10^6,1\le l\le r\le n,1\le h\le 10^9,1\le x\le n,1\le y\le 10^{18}\)


整體二分很 trivial,這里就不說了;注意可以通過奇怪的技巧減少修改次數(嗎?)

另一種比較巧妙的做法是,將詢問和修改離線到序列上,對序列進行掃描線,然后在詢問上維護數據結構並進行二分,復雜度就可以做到 \(O(n\log n)\)但是實際上這個跑得還沒有整體二分快......

主要還是利用了區間修改,單點詢問的性質。

「USACO04JAN」有序奶牛

題目鏈接:DarkBZOJ


題目就是要求我們簡化有向圖,使得圖對應的偏序關系(對應可達性)不改變。

考慮暴力枚舉邊並判斷連通性,從而確定某條邊是否可以被刪除。這樣我們需要確定一個順序。交換論證可以說明,當終點按照拓撲序從小到大,相同時按照起點拓撲序從大到小排序是最優的。使用 bitset 判斷連通性即可。

「WC2010」重建計划

題目鏈接:洛谷


注意一下,如果直接使用單調隊列會出問題。復雜度分析出來是 \(\max\{dep_{\max},dep_{\operatorname{cur}}\}\)。如果 \(dep_{\max}\) 不幸地出現在了首位,並且比較大,並且子樹比較多,並且數據被精心構造,那么就會被卡掉。

解決辦法是人為控制順序,排個序讓 \(dep_{\max}\) 靠后出現,也就是按照 \(dep\) 從淺到深排序即可。

總結:准確分析復雜度,同時復雜度也可以指導優化方向,也就是規避糟糕的情況或者減小碰到的概率。

「CodeChef18Jun」 Archi and Tree

題目鏈接:Vjudge


容易發現,問題相當於在樹上的一條路徑上覆蓋一個一次函數,最終需要對於每個點,求出覆蓋到它的一次函數在它那里能取到的最小值。

容易想到樹剖后維護李超樹的算法,但時間復雜度是 \(O(n\log^3n)\) 的,目測難以通過。

另外一種想法是,注意到詢問在修改之后才進行,我們可以使用倍增維護標記。此外,由於李超樹本身只依賴於決策單調性和分治結構,因此在倍增對應的結構上,“李超樹”也是可以被維護的。

最后就只需要在全部修改結束后,從長到短下放標記信息即可。

復雜度瓶頸在下放,最終復雜度為 \(O(n\log^2n)\)

「CF1383A」String Transformation 1

題目鏈接:CF


研究最值問題,一種方法是去分析上下界當然應當先得到正確的問題

比如此題,我們可以把轉移關系變成圖 \(G_1\)。我們需要得到一個 \(G_2\),使得 \(G_2\) 上偏序關系是 \(G_1\)超集,且 \(G_2\) 上具有最少的邊。

分析下界——若圖上有 \(n\)連通塊,則下界是 \(26-n\),因為每個大小為 \(S\) 的弱連通塊內部需要至少 \(S-1\) 條邊才可以保證弱連通,否則一定和 \(G_1\) 不同。

另一方面,我們發現我們也可以構造出一種方案——按照每個弱連通塊內的拓撲序構造一條鏈即可。因此這個下界可以被取到。

「CodeJam21 R3」Square Free

題目大意:給定一個 \(n\times m\) 的方格,要求在每個格子里放入左斜杠 / 或者右斜杠 \。每一行和每一列的斜杠數是預先確定的。此外,還要滿足不能存在斜杠構成的斜正方形。求一種構造方案。

下面兩種方案中都含有斜正方形:

\///
/\\/
///\
//\/
----
//\\
//\\
\///
/\//

對於 \(100\%\) 的數據,滿足 \(1\le n,m\le 20\)


主要體現的是調整的思想

我們可以先隨便構造出一種符合數量限制的方案。此時這個方案中可能存在正方形,我們就需要調整方案——將它們破壞掉。注意到正方形是一個數量上行列都對稱的圖形,每一行、每一列上所包含的正方形上的左斜杠數就等於右斜杠數。因此,我們可以將 /\ 對換,從而消去這個正方形。如果還有正方形,繼續這個過程。

假設 / 的字典序大於 \,那么破壞正方形的時候,整個方案的字典序會變小,因此調整過程一定會結束。更進一步,字典序最小的方案中一定不含任何正方形,因此我們去求出這樣一個方案即可。

總結:注意調整思想,觀察圖像性質


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM