雜題選做Ⅱ


由於換了台電腦,而我的貪心 & 構造能力依然很拉跨,所以決定再開一個坑(

upd on 2021.11.30:由於更到后面發現后面的題目和貪心、DP 之類的關系不算太大了,倒是混入了不少計數題,故改名“雜題選做”,但是為了避免連接出鍋還是保留原來的 url。

前傳:

u1s1 我預感還有Ⅲ(欸,這不是我在多項式Ⅱ中說過的原話嗎)

24. P5912 [POI2004]JAS

一開始直接莽了個點分治,當我測過了樣例美滋滋地一交,發現自己獲得了 20 分的好成績之后,才發現事情有那么億點點不對勁(

不難發現,題目等價於求高度最小的點分樹的高度,直接求有點困難,我們不妨來對其進行一些轉化:我們考慮給每個點一個標號,那么問題可以轉化為,求使得任意兩個標號相同的點之間必須有一個點標號比它大,求最大標號的最小值。

考慮 DFS,DFS 到一個節點 \(x\) 時我們考慮貪心地給它賦上一個最小的標號,那么要求這個標號滿足:

  • 對於所有子樹內與該點標號相同的點 \(y\)\(x\)\(y\) 之間至少有一個點編號比它大。
  • 對於 \(x\) 不同子樹內的兩點 \(y,z\),如果 \(y,z\) 標號相同並且 \(y,z\) 路徑上不存在標號比 \(y\) 的標號大的點,那么 \(x\) 的標號比這樣的點 \(y\) 的標號都要大。

注意到點分樹高度肯定是 \(\log n\) 級別的,因此直接模擬即可。每次用個 mask 記錄下所有滿足存在一個點 \(y\) 標號為 \(p\),且 \(y\to x\) 路徑上的點的標號都 \(\ge p\)\(p\) 的集合 \(S_1\),再記錄下所有滿足存在兩點 \(y,z\) 屬於 \(x\) 的不同子樹,它們的標號都為 \(p\),且 \(y\to z\) 路徑上不存在標號 \(\ge p\)\(p\) 的集合 \(S_2\),然后貪心地取 \(>S_2\) 中最大元素,且不在 \(S_1\) 中地元素作為 \(x\) 的標號。

時間復雜度 \(\Theta(n\log n)\)

25. P3545 [POI2012]HUR-Warehouse Store

大概是模擬費用流板板題?

看到這種按時間軸進行的操作,我們通常可以按照事情發展的順序進行貪心/反悔貪心。我們不難想到這樣一個很 naive 的貪心:從前往后考慮所有操作,每次令答案加上 \(a_i\),如果能付得起 \(b_i\) 件商品那就滿足這個顧客的需求,不過這樣貪心顯然是錯誤的,因此我們考慮魔改它,也就是采用反悔貪心的思想。我們再用個堆維護目前被滿足需求的顧客的 \(b_i\),每次取出最大的這樣的 \(b_i\),我們不妨設之為 \(b_j\),那么如果 \(b_j>b_i\),並且去掉 \(b_j\) 以后剩余的庫存能夠滿足 \(i\) 的需求,那么我們就不滿足 \(j\) 的需求,改滿足 \(i\) 的需求,根據費用流的思想可知該算法的正確性。

時間復雜度 \(\Theta(n\log n)\)

26. P2587 [ZJOI2008]泡泡堂

不難發現最大值與最小值情況類似,因此下面只討論最大值的情況,最小值的情況簡單鏡像一下即可。

考慮將浙江隊所有選手的實力從大到小排序,然后我們貪心地先讓盡可能多的浙江選手得 \(2\) 分,具體來說,我們按照實力順序從大到小遍歷每個浙江選手,然后在敵方選手的 multisetlower_bound 一下找到小於該浙江選手且實力最高的敵方選手,然后將其從 multiset 中刪除。

匹配完得分為 \(2\) 的浙江選手后,我們考慮盡量讓剩余的浙江選手得分為 \(1\),這部分就比較簡單了,直接貪心令同分的浙江選手與地方選手匹配,使用 map 維護即可。

時間復雜度 \(\Theta(n\log n)\)

27. P3620 [APIO/CTSC 2007] 數據備份

其實感覺類似的反悔機制還是挺喜聞樂見的罷(

考慮用個 set 維護相鄰兩個未被選擇的辦公樓及它們之間的距離,然后每次取出距離最小的相鄰辦公樓,不妨設之為 \(l,r\),那么根據我們貪心的策略,此時 \(l+1\sim r-1\) 肯定按照 \(l+1,l+2\)\(l+3,l+4\)\(\cdots\)\(r-2,r-1\) 的方式配對的,而加入 \(l,r\) 之后我們肯定按照 \(l,l+1\)\(\cdots\)\(r-1,r\) 的方式配對,直接減去 \([l+1,r-1]\) 的貢獻加上 \([l,r]\) 的貢獻即可。

時間復雜度 \(n\log n\)

28. CF884F Anti-Palindromize

怎么……現在費用流都能混到我的這個 blog 里了呢(

考慮建立三排節點,第一排節點包含每種字符,即我們先對每種字符新建一個節點 \(x\),並連一條 \(S\to x\),容量為 \(c_x\),費用為 \(0\) 的邊,其中 \(c_x\)\(x\)\(s\) 中的出現次數。第二排節點包含所有二元組 \((p,c)\),對於第一排的所有節點 \(c\),我們都連一條其到 \((p,c)\),容量為 \(2\) 的邊,其中 \(p\in[1,n]\)。第三排包含所有原字符串中的位置,對每個二元組 \((p,c)\),如果 \(s_p=c\) 則連一條 \((p,c)\to p\),容量為 \(1\),費用為 \(b_p\) 的邊,同理如果 \(s_{n+1-p}=c\) 則連一條 \((p,c)\to n-p+1\),容量為 \(1\),費用為 \(b_{n+1-p}\) 的邊,最后再從第三排所有節點向匯點 \(T\) 連容量為 \(1\) 費用為 \(0\) 的邊,跑最大費用最大流即可。

時間復雜度 \(O(\texttt{能過})\)

29. P3045 [USACO12FEB]Cow Coupons G

一開始感覺這題和遠古時期做的 CF436E 很像,然后就一直往那道題的方向想,結果沒想出來,心態爆炸/dk

首先考慮一個非常淺顯易懂的性質:如果前足夠買得下折扣價最低的 \(k\) 頭奶牛,那么這 \(k\) 頭奶牛肯定都會至少以折扣價被買走,否則我們肯定可以調整策略使答案更優。

因此這樣我們首先將所有奶牛按它們的折扣價排序,並令答案減去折扣價最便宜 \(k\) 頭的奶牛的價格之和,如果某一次減掉某頭奶牛的折扣之后,總價格被減到了 \(0\) 以下,那么就直接輸出當前已有的奶牛個數。

然后考慮如何使用剩余的前買下更多的奶牛。不難發現,如果我們多買下了一頭奶牛,那么只有兩種可能,一是以原價買下,代價就是 \(p_i\),二是以折扣價買下,但是由於我們總共只有 \(k\) 張折扣券,因此代價不能簡簡單單地視作 \(c_i\),而要先將某個使用了折扣券的奶牛改為原價購買,再對該奶牛使用折扣券,代價為 \(c_i+\min\limits_{x\text{使用了折扣券}}p_x-c_x\),不難發現這兩部分都可以使用堆維護,具體來說,我們建立三個堆 \(q_1,q_2,q_3\),其中 \(q_1\) 存儲現在啥也沒買的那些牛的 \(p_i\)\(q_2\) 存儲現在啥也沒買的那些牛的 \(c_i\)\(q_3\) 存儲現在以折扣價購買了的那些牛的 \(p_i-c_i\),這樣兩種情況代價的較小者可在 \(\Theta(1)\) 的時間內求出,總復雜度 \(\Theta(n\log n)\)

30. CF1500C Matrix Sorting

一道非常妙的拓撲排序好題,能出出這道題的人怕不是神仙/bx

首先我們考慮求出矩形 \(A\) 中的每一行在進行這些操作后會對應到矩形 \(B\) 中的哪一行——顯然如果矩形 \(A\) 中每行都不相同,那直接相同的行配對即可,如果矩形 \(A\) 出現了相同的行,那顯然它們的相對位置順序是不會改變的,直接按照它們在原矩陣中的順序編號即可。這樣我們可以新增一個 \(m+1\) 列,\(A\) 矩形第 \(i\) 行第 \(m+1\) 列的元素就是 \(i\),而 \(B\) 矩形第 \(i\) 行第 \(m+1\) 列的元素則是 \(B\) 矩形第 \(i\) 行在 \(A\) 矩形中對應的行的編號。當然如果無法對應我們就直接輸出 NO

接下來考慮如何求出操作序列,我們倒着考慮操作序列,那么可以發現,我們最后一步可能操作的列,在 \(B\) 矩形中都是單調不降的,也就是說對於任意相鄰兩行 \(i,i+1\),必須要有 \(b_{i,j}\le b_{i+1,j}\) 后,最后一次才有可能操作第 \(j\) 列,考慮完了最后一次操作,再考慮倒數第二次操作的列有什么限制,還是必須單調不降嗎?非也,不難發現,加入最后一次操作的列為 \(x\),倒數第二次操作的列為 \(y\),那么如果 \(b_{i,y}>b_{i+1,y}\)\(b_{i,x}<b_{i+1,x}\),這種情況還是有可能合法的,因為雖然排 \(y\) 之后會導致 \(i,i+1\) 順序顛倒,但是下一次排序我們又把它搬回來了,因此這種情況是不影響的,但是如果出現 \(b_{i,y}>b_{i+1,y}\)\(b_{i,x}=b_{i+1,x}\) 就 GG 了,因為我們的排序是 stable 的,你前一次把 \(i,i+1\) 的順序搞反了,后一次兩行的關鍵字相同,它們的順序還是反的。

那么我們應該從什么角度思考這個過程呢?不難發現,我們倒着考慮每一次操作 \(x\),那么我們考慮完 \(x\) 之后,相當於把所有 \(a_{i,x}\ne a_{i+1,x}\)\((i,i+1)\) 都“解鎖了”,而如果考慮到某一步操作時,第 \(y\) 列存在一個 \(i\) 使得 \(a_{i,y}>a_{i+1,y}\),且 \((i,i+1)\) 沒有被“解鎖”,那么上一步操作的就不可能是 \(y\),因此我們可以考慮拓撲排序的過程,將相鄰兩行和每一列看作一個點,對於每對 \((a_{i,x},a_{i+1,x})\),如果 \(a_{i,x}<a_{i+1,x}\),那么我們連一條第 \(x\) 列向第 \(i\) 行的邊,表示操作完第 \(x\) 列后 \((i,i+1)\) 就被解鎖了,如果 \(a_{i,x}>a_{i+1,x}\),那么我們連一條第 \(i\) 行指向第 \(x\) 列的邊,表示第 \(i\) 行被解鎖,是第 \(x\) 列能夠被操作的必要條件,然后跑一遍類似拓撲排序的東西即可。只不過這里與一般的拓撲排序不同的一點是,如果一個點對應的是某一行表示的點,那么只要連向它的點中至少一個被選擇,那它就可以設為被訪問。

那么怎樣統計答案呢?不難發現,初始局面相當於我們強制對 \(m+1\) 行排了個序,因此我們只需檢驗 \(m+1\) 列對應的點是否被訪問即可,如果被訪問了則倒着輸出拓撲序列,否則輸出 NO

時間復雜度 \(\Theta(nm)\)

31. CF280D k-Maximum Subsequence Sum

一開始看到題面,\(q\) 次詢問?求 \(k\) 個不交區間的和的最大值?還帶修?什么毒瘤,后來才發現我忽略了 \(k\le 20\) 的條件……無語了(

看到這個 \(k\le 20\) 我們可以很自然地聯想到 NOI2011 超級鋼琴 那道題,也進而可以設計出一個大致地框架:我們先將整個區間放到一個優先隊列中,然后每次貪心地多選一個區間,取價值最大的選擇方式,如此重復 \(k\) 步。

那么如何實現這個程序呢?一個非常 naive 的想法是,我們將當前沒有被選擇的區間放入一個優先隊列,每次取所有這樣的區間中,最大子段和最大的區間,然后將這段區間中和最大的 subarray 設為被選擇,然后將旁邊兩個子段插入優先隊列,但是這樣顯然是錯誤的,樣例都過不去,因為樣例恰好選擇了整個數組,而按照上述算法,擴展完一步以后就不會繼續擴展了,這就導致 \(k=1\)\(k=2\) 答案相同。那么有什么補救方法呢?考慮反悔貪心。具體來說,我們增加一種擴展區間的方法:扣掉某個已經選擇的區間的最小子段和,這個同樣可以用堆維護。注意如果新增的價值 \(<0\) 就直接 break 掉。

時間復雜度 \(\Theta((n+q)\log n+Bk\log n)\),其中 \(B=10^4\) 表示操作次數。

32. CF1373G Pawns

首先我們假設第 \(i\) 個棋子最終擺在第 \(k\) 行第 \(p_i\) 列,那么顯然一組 \(\{p_i\}\) 符合要求的必要條件是 \(p_i\) 互不相同,且 \(p_i\ge y_i+|x_i-k|\)

同時不難證明這也是充分條件,具體構造就是從 \(y_i\) 大的開始依次歸位。

這樣一來問題就變得很容易了,用個線段樹維護 \(cnt_i\) 表示有多少個 \(y_j+|x_j-k|\ge i\),那么答案就是 \(\max cnt_i+i-1\),這個用線段樹維護即可。

時間復雜度 \(q\log m\)

33. CF1428G2 Lucky Numbers (Hard Version)

首先這題雖然有個多組詢問,但每次詢問都是一個數並且都不大,所以我們肯定會提前把所有 \(x\) 的答案都預處理出來然后 \(\mathcal O(1)\) 處理每個詢問。

那么如何預處理每個 \(x\) 的答案呢?首先我們考慮一個不太對的多重背包做法:不難發現每一位的貢獻可以拆開來統計,因此考慮對於每一位,我們統計拆出來的 \(k\) 個數中,這一位上所有數字的和。我們設 \(10^d\) 位拆出的所有數各位數字和為 \(s_d\),那么我們肯定希望 \(s_d\) 盡量是 \(3\) 的倍數,而如果 \(s_d=3t\),那么這一位的貢獻都是 \(t·f_d\),這個可以考慮建 \(3k\) 個體積為 \(3·10^d\),價值為 \(f_d\) 的物品然后跑多重背包。

但是這樣顯然無法正確處理 \(x\) 不是 \(3\) 的倍數的情況。怎么辦呢?考慮一個非常顯然的性質:對於每一位,拆出的 \(k\) 個數中,最多只有一個數這一位上的數不是 \(3\) 的倍數,否則我們肯定可以調整,譬如 \(4+7\) 可以調整成 \(2+9\)。而且我們如果把那些不是 \(3\) 的倍數的位都放到一位上,肯定是不影響答案的,因此我們考慮枚舉包含不是 \(3\) 的倍數的位對應的數是什么,設為 \(x\),計算出 \(x\) 的價值,然后把 \(dp_x\) 的初值設為 \(x\) 的價值,然后再跑多重背包即可,注意此時每種物品的個數應為 \(3(k-1)\)

為什么只講 G2 呢?因為 G1 被我用暴力 \((10^6)^2·6\) 的數位 dp 艹過去了就沒啥好說的了(

34. CF1452F Divide Powers

一道非常妙的貪心好題,給出題人點個贊/qiang

首先特判掉 \(-1\) 的情況,顯然如果 \(\sum\limits_{i=0}^{n-1}cnt_i2^i<k\) 答案就是 \(-1\)

考慮多出一個 \(\le 2^x\) 可能是哪些情況造成的,不難發現無非就三種情況:

  1. 某個 \(\le 2^x\) 經過了若干次拆分分成了一些更小的冪,那么顯然每進行一次操作就會多出一個 \(\le 2^x\) 的冪,因此 \(t\) 次操作后會多出 \(t\)\(\le 2^x\) 的冪。
  2. 某個 \(>2^x\) 的冪 \(2^y\) 經過若干次拆分完全變成了 \(\le 2^x\) 的冪,不難發現這部分會恰好經過 \(2^{y-x}-1\) 次操作將 \(2^y\) 變成 \(2^{y-x}\)\(2^x\)。后面部分則可以歸約到 1 操作。
  3. 某個 \(>2^x\) 的冪經過若干次操作部分分解為 \(\le 2^x\) 的冪,譬如 \(x=2\),那么可將 \(2^4\) 拆分成 \(2^3+2^2+2^2\)

對於這類貪心問題,我們不妨從性價比的考慮這三個操作。可以發現,\(1\) 操作性價比 \(=1\)\(2\) 操作性價比 \(>1\),而 \(3\) 操作性價比肯定不超過 \(1\),因此我們肯定貪心地選擇盡可能多地進行 \(2\) 操作。我們考慮從小到大遍歷每個 \(>2^x\) 的冪,先盡量用 \(2\) 操作將其拆成 \(\le 2^x\) 的冪,如果我們發現拆一個 \(>2^x\) 的冪時,能夠補完全部 \(\le 2^x\) 的冪,那么我們此時再使用 \(2\) 操作就不一定是最優的,我們就考慮拆這個冪,不妨設之為 \(2^y\),那么我們考慮用 \(3\) 操作拆這個冪,同時記錄下如果我們使用 \(1\) 操作,最多可以拆出多少個 \(1\),然后邊拆邊更新答案即可。

時間復雜度 \(\Theta(qn)\)

35. CF232C Doe Graphs

代碼 10 分鍾,debug 兩小時

又是精神崩潰的一天/dk

首先這個 Doe 圖是遞歸構造的,因此我們也可以嘗試考慮遞歸地求解某些量,進而計算出答案,可以發現,在一個 \(n\) 階 Doe 圖中,有兩個點是非常特殊的:\(1\)\(|D_n|\),因為只有經過它們才能進入其他 Doe 圖,因此我們考慮設 \(F(n,x)\) 表示在一個 \(n\) 階 Doe 圖中,\(x\)\(1\) 的最短距離,再設 \(G(n,x)\) 表示在一個 \(n\) 階 Doe 圖中,\(x\)\(|D_n|\) 的最短距離,考慮如何遞歸地求解 \(F,G\)

  • 如果 \(x\le\text{fib}_{n-1}\),則意味着 \(x\) 在左半邊的 \(D_{n-1}\) 子圖中,那么 \(x\)\(1\) 有兩種可能,要么直接在左半邊的子圖內走到 \(1\),要么先走到 \(|D_{n-1}|\),再走到 \(|D_{n-1}|+1\),最后再走到 \(1\),注意,后面那種情況很容易忽略,我因為忽略了后者而瘋狂 WA 14。\(x\)\(|D_{n}|\) 則只能要么先走到 \(1\),要么先走到 \(|D_{n-1}|\),再走到 \(|D_{n-1}|+1\),再在右邊的子圖內走到 \(D_{n}\),而打個表可以發現,在 \(D_n\) 中,\(1\)\(|D_n|\) 的最短距離為 \(\lceil\dfrac{n}{2}\rceil\),因此在右邊子圖中經過的最短距離就是 \(\lceil\dfrac{n-2}{2}\rceil\)
  • 如果 \(x>\text{fib}_{n-1}\),那么 \(x\)\(1\) 肯定會先在右邊子圖內走到 \(|D_{n-1}|+1\),再一步走到 \(1\),而 \(x\)\(|D_n|\) 則只能在右半部分走,到左半部分肯定是不優的,這個同樣可以遞歸求出。

這樣單次求解 \(F/G\) 的復雜度就降到了 \(\Theta(\log n)\),接下來考慮如何求解答案,我們設 \(H(n,a,b,len)\) 表示在 \(n\) 階 Doe 圖中,\(1\)\(D_n\) 之間連了一條長度為 \(len\) 的鏈(注意,這種情況同樣也很容易忽略,事實上,如果你點開 test 6 的數據,你發現在 \(D_{1000}\) 中,\(1\)\(13\) 的距離不是 \(D_5\)\(1\)\(13\) 的距離 \(3\),而是 \(2\),因為可以 \(1\to 14\to 13\),這時候 \(1\)\(13\) 之間就可以視作連上了一條長度為 \(2\) 的鏈),\(a\)\(b\) 之間的最短距離。還是分三種情況考慮:

  • 如果 \(a,b\) 都在左子圖內,直接遞歸左子圖內,即 \(H(n-1,a,b,2)\)

  • 如果 \(a,b\) 都在右子圖內,到右子圖內遞歸,\(H(n-2,a-\text{fib}_{n-1},b-\text{fib}_{n-1},len+1)\)

  • 如果 \(a,b\) 一個在左子圖內,一個在右子圖內,那么我們計算答案,分三種情況:

    • \(a\to 1\to |D_{n-1}|+1\to b\)
    • \(a\to |D_{n-1}|\to|D_{n-1}|+1\to b\)
    • \(a\to 1\to |D_n|\to b\)

    分別討論一下即可。三種情況的答案均可通過調用 \(F/G\) 函數算出。

總復雜度 \(\Theta(q\log n)\)

36. CF1572B Xor of 3

怎么評價這個題嘛……過了是過了,但是始終不能理解我的做法/wul,甚至完全不會證它的正確性,反正就硬核着杠了一大坨分討就過了(

首先,如果 \(1\) 的個數為奇數,那么由於每次操作不會改變序列中 \(1\) 的個數的奇偶性,因此肯定無法將序列中所有元素均變為 \(0\)

而如果 \(1\) 的個數為偶數,也不一定存在合法解,詳情見樣例的第三組數據(

那么我們如何判定是否存在合法解以及構造出符合要求的解呢?首先特判掉全部為 \(1\) 的情況,此時必然不存在合法解。而對於更普適的情況,我們先求出每個全部由 \(1\) 組成的連續段,假設為 \([l_1,r_1],[l_2,r_2],\cdots,[l_m,r_m]\),那么我們考慮從左到右依次消除每個連續段,分情況討論:

  • 如果我們待消除的這個連續段 \([l_i,r_i]\) 長度為偶數,那么如果 \(l_i\ne 1\),直接依次執行 \(l_i-1,l_i+1,l_i+3,\cdots,r_i-1\) 即可搞定這個連續段,否則依次執行 \(r_i-1,r_i-3,\cdots,l_i\) 也可搞定這個連續段。由於 \(a_i\) 不全為 \(1\),所以 \(l_i=1\)\(r_i=n\) 不同時成立,因此構造合法。
  • 如果我們待消除的連續段長度為奇數,這部分比較麻煩。設 \(d\) 為當前連續段右端點與下個連續段左端點的距離,繼續分情況討論:
    • 如果 \(d\) 為偶數,那么我們依次執行 \(r_i,r_i+2,\cdots,l_{i+1}-4,l_{i+1}-2,l_{i+1}-4,l_{i+1}-6,\cdots,l_i+2,l_i\) 即可將 \([l_i,r_i]\) 全部變為 \(0\),同時將下一連續段的長度減一。
    • 如果 \(d\) 為奇數,繼續分類討論:
      • 如果這一段左端點不是 \(1\),那么依次執行 \(l_i-1,l_i+1,l_i+3,\cdots,r_i-3,r_i,r_i+2,\cdots,l_{i+1-3},r_i-1,r_i+1,r_i+3,\cdots,l_{i+1}-2\),這樣也可達到將 \([l_i,r_i]\) 全部變為 \(0\),同時將下一連續段的長度減一的效果。
      • 如果這一段左端點是 \(1\),那么我們會選擇用下一段去消當前這一段,分情況討論:
        • 如果 \(r_{i+1}=n\),那么無解。
        • 如果 \(r_{i+1}-l_{i+1}+1\) 為奇數,那么我們依次執行 \(r_i,r_i+2,\cdots,l_{i+1}-3,r_{i+1}-1,r_{i+1}-3,\cdots,l_i\),這樣可以將兩段同時消沒。
        • 如果 \(r_{i+1}-l_{i+1}+1\) 為偶數,那么我們依次執行 \(r_i,r_i+2,\cdots,l_{i+1}-3\),這樣可將兩段合並起來,作為新的 \([l_{i+1},r_{i+1}]\)

於是這道思維題成功被我做成了一道大分類討論題(大霧

時間復雜度線性。

37. CF1572C Paint

看到這種對一個連續段進行個啥操作的題,我們通常可以想到區間 DP。此題也不例外,我們設 \(dp_{l,r}\) 表示最少進行多少次操作即可將 \([l,r]\) 全部變為 \(a_r\),思考如何轉移:

  • \(dp_{l,r}\leftarrow\min(dp_{l+1,r},dp_{l,r-1})+1\),很容易想到。
  • 枚舉端點 \(a_i=a_r\),那么 \(dp_{l,r}\leftarrow dp_{l,i}+dp_{i+1,r}\),也就是將序列拆成兩段分別染色然后合並的套路。這樣轉移看似復雜度不對,但由於題目保證每種顏色最多出現 \(20\) 次,因此我們可以通過記錄 \(pre_i\) 表示 \(i\) 前面離 \(i\) 最近且顏色與 \(i\) 顏色相同的位置,這樣轉移可以做到 \(20n^2\)

容易發現所有最優策略都可以通過以上兩個操作或者通過針對以上兩個操作的調整得到,因此上述 DP 的正確性是可以保證的,復雜度 \(20n^2\)

38. CF1572D Bridge Club

乍一看到這個題我頓時樂了,\(Q_n\)__builtin_parity 染色之后顯然是一個二分圖,因此原題等價於二分圖最大權匹配,直接費用流……

然后一看數據范圍,\(n\le 20\),這意味着點數 \(\le 2^{20}\),頓時傻眼,玩個錘子(

事實上我們發現 \(m\le 200\),因此我們猜測可能在最大權匹配上的邊數並不是太多,大概頂多是 \(m\) 或者 \(mn\) 級別的,事實的確如此,可以證明有用的邊數上界為 \(m(2n-1)\),因為減少一條邊最多減少 \(2n-1\) 個匹配,故隨便取 \(m(2n-1)\) 條邊必然存在一個大小為 \(m\) 的匹配。

這樣一來事情就容易許多,直接貪心地找最大的 \(m(2n-1)\) 條邊,把涉及到的點作為關鍵點拎出來跑費用流即可。注意找最大的 \(m(2n-1)\) 條邊不能使用堆,最好使用 nth_element,否則可能會 MLE(

39. P6663 [POI 2019] Układ scalony

咦?怎么學校模擬賽的題也混到我博客里了(

首先不難發現構造出的樹的直徑有個下界,考慮如何求出這個下界,顯然這個下界不低於 \(n+m-2\) 對吧,因為 \((1,1)\)\((n,m)\) 的距離就已經達到了 \(n+m-2\),因此我們肯定盡量希望直徑長度盡可能接近這個值。可以發現,如果 \(n\) 為奇數,那么我們可以按照如下的方式使樹的直徑達到 \(n+m-2\)

對於 \(m\) 為奇數的情況也是同理,只需在上圖中將圖關於 \(y=x\) 進行一次翻折即可。

\(n,m\) 均為偶數的情況,通過觀察 \(n=m=2\) 以及 \(n=2,m=4\) 的情況我們大膽猜測,無法構造出直徑為 \(n+m-2\) 的方案,因此對於 \(n,m\) 為偶數的情況,直徑的下界就是 \(n+m-1\)

接下來考慮如何根據直徑下界構造出合法的解,下面不妨假設 \((n-1)m\) 為偶數,也就是說如果 \(n,m\) 中至少有一個為奇數,那么 \(n\) 為奇數。考慮分情況討論:

\(d\le 2(n-1)+(m-1)\),那么我們在只需在上圖的基礎之上稍微做一些改動,有以下兩種可能:

  • 如果 \(d\le (n-1)+(m-1)+\dfrac{n-1}{2}\),那么我們斷開 \((\dfrac{n+1}{2},1)\)\((\dfrac{n+3}{2},1)\) 之間的邊,連上 \((\dfrac{n+3}{2},1)\)\((\dfrac{n+1}{2}-(d-(n-1)-(m-1)),1)\) 之間的邊。
  • 如果 \(d>(n-1)+(m-1)+\dfrac{n-1}{2}\),那么我們斷開 \((\dfrac{n+1}{2},1)\)\((\dfrac{n+3}{2},1)\) 之間的邊,連上 \((\dfrac{n+3}{2},1)\)\((1,1)\) 之間的邊。再斷開 \((\dfrac{n+1}{2},m)\)\((\dfrac{n+3}{2},m)\) 之間的邊,連上 \((\dfrac{n+3}{2},m)\)\((\dfrac{n+1}{2}-(d-((n-1)+(m-1)+\dfrac{n-1}{2})),m)\) 之間的邊。

直接用這些公式描述連斷邊的情況可能不太直觀,借助下圖 \(n=5,m=6,d=12\) 的構造可能可以更好地理解。

\(d>2(n-1)+(m-1)\),那么我們先從 \((n,1)\) 開始,連接 \((n,1),(n-1,1)\) 的邊、\((n-1,1),(n-2,1)\) 的邊,……,\((2,1),(1,1)\) 的邊,\((1,1),(1,2)\) 的邊,\((1,2),(1,3)\) 的邊,……,\((1,m-1),(1,m)\) 的邊,\((1,m),(2,m)\) 的邊,\((2,m),(3,m)\) 的邊,……,\((n-1,m),(n,m)\) 的邊,然后在中間部分反復徘徊直到直徑長度達到 \(d\),對於剩余的點直接連向它上方的節點即可,例如 \(n=5,m=6,d=23\) 的情況可以按照如下方式構造:

直接模擬即可。時間復雜度 \(\Theta(nm)\)

啟示:有的構造題可以嘗試從邊界狀態入手給出邊界狀態的構造,然后通過調整得到我們想要的構造。

40. CF991F Concise and clear

我為什么會手賤點開這個分類討論屑題啊(

分類討論。記 \(D(x)=\lceil\log_{10}(x)\rceil\) 表示 \(x\) 在十進制表示下的位數,那么一個比較淺顯的性質是 \(D(ab)=D(x)=\lceil\log_{10}(ab)\rceil\le \lceil\log_{10}(a)\rceil+\lceil\log_{10}(b)\rceil+1\),而后者表示將 \(ab\) 寫成 “a*b" 這種形式所需要的字符數,這也就說明將 \(ab\) 寫成 a*b 的形式肯定是不如直接寫 \(ab\) 來得優的,因此稍加分析我們發現最優表達方式無非以下幾種:

  • \(a\)
  • \(a^b\)
  • \(a\times b^c\)
  • \(a\times b^c+d\)
  • \(a\times b^c+d^e\)
  • \(a^b\times c^d\)
  • \(a^b\times c^d+e\)

對於第一種情況,可能的情況顯然只可能是 \(n\),對於第二、三、四種情況我們枚舉 \(a,b,c\) 然后更新答案,由於 \(c\ge 2\),因此 \(b\) 只用枚舉到 \(\sqrt{n}\),直接枚舉顯然會 TLE,不過如果加上”如果當前 \(a\times b^c\) 所需要的位數大於等於當前最優表示法的位數就 break“這一剪枝就能跑得飛起。對於第六種情況,可能的 \(a,b,c,d\) 並不是很多,可以直接枚舉 \(a,b,c,d\),如果 \(a\) 或者 \(c\) 不是 \(n\) 的質因子就跳過,如果 \(D(a)+D(b)+3\) 大於等於當前最優答案就跳過不枚舉 \(c,d\)。對於第 \(5,7\) 種情況,由於當 \(n=10^{10}\) 時答案就是 \(10^{10}\),而對於其他情況 \(n\) 的位數 \(\le 10\),如果 \(a,b,c,d,e\) 有一個是兩位數,那么 \(a\times b^c+d^e\)\(a^b\times c^d+e\) 的位數就 \(\ge 10\),不是最優解,因此 \(a,b,c,d,e\) 一定是一位數,直接枚舉即可。

41. CF883B Berland Army

首先正反一遍 BFS 求出每個點能填的權值的范圍 \([l_i,r_i]\)

考慮貪心地盡量讓每個點填的權值靠近 \(r_i\),具體來說我們從小到大枚舉每個值 \(x\in[1,k]\),然后用個 set 動態維護下所有 \(l_i\le x\)\(r_i\),分情況討論:

  • 如果存在一個 \(i\) 滿足 \(r_i=x\)\(i\) 沒有被賦值,那么我們將所有這樣的 \(i\) 都賦上 \(x\),使用 set 維護即可。
  • 如果不存在上述 \(i\),那么我們在 setlower_bound 找出 \(r_i>x\)\(r_i\) 最小的 \(i\),然后在 \(i\) 上賦上 \(x\)
  • 如果第二個條件也無法滿足,則輸出 \(-1\)

時間復雜度 \(m\log n\)

42. BZOJ #2264. Free Goodies

一開始以為直接模擬就行了,寫了一半才發現相當不對勁……

我們考慮將所有物品按 \(a_i\) 從大到小排序,如有多個 \(a_i\) 相同的則再按 \(b_i\) 升序排序,那么可以發現,如果我們確定了每次 Jan 的選擇,那么 Petra 每次的選擇都是固定的:取當前沒有被選擇的物品中最靠前的。

如果我們把 Jan 的選擇視作右括號,把 Petra 的選擇記作左括號,那么在一個合法的取物品方案中,任意一個前綴中右括號個數必然 \(\le\) 左括號個數,因此我們可將問題轉化為一個類似括號序列的東西,即我們貪心地取走 \(\lfloor\dfrac{n}{2}\rfloor\) 個右括號,使得將沒有選擇的括號都替換為左括號后,得到的括號序列中任意一個前綴的右括號個數 \(\le\) 左括號個數。考慮貪心,每次取出一個可以取的位置中 \(b_i\) 最大的,如果有 \(b_i\) 相同則取 \(a_i\) 最小的,用線段樹維護這個貪心即可,具體來說,我們先把已經欽定的位置中,左括號視作 \(1\),右括號視作 \(-1\),然后在線段樹上二分找到最靠右的 \(\le 1\) 的位置 \(p\),然后在 \([p+1,n]\) 中查詢 \((b_i,-a_i)\) 的最大值即可。

最后還有個小問題:如何處理先后手的問題。不難發現如果先手是 Petya 我們這樣直接貪心就是正確的,否則我們考慮添加一個 \(a_i=\infty,b_i=0\) 的物品,然后將先手變為 Petya,並且令 Petya 第一次取的物品不計入 Petya 取的物品的總價值,這樣就可以按照上面的過程貪心了。

時間復雜度 \(\Theta(n\log n)\)

43. P3269 [JLOI2016]字符串覆蓋

一道非常神仙的貪心題 %%%%%%%%%%%%%%%%%%%

首先求出每個給出的子串在 \(S\) 中的出現位置,這個可以通過字符串哈希實現,不妨設第 \(i\) 個字符串所有出現位置的左端點為 \(p_{i,1},p_{i,2},\cdots,p_{i,c_i}\)

考慮如何求出所有字符串覆蓋的位置的並的最大值,注意到題目一個非常關鍵的條件:\(n\le 4\)。考慮枚舉所有字符串起點的大小關系,這個 \(n!\) 枚舉一下即可,再枚舉相鄰字符串兩兩之間是否重疊,同樣 \(2^{n-1}\) 枚舉一下,考慮如何貪心地對每種情況安排每個字符串的啟示問題,對於相鄰兩字符串 \(i,i+1\),如果它倆不重疊,那么我們肯定盡量希望 \(i+1\) 放置的位置盡可能靠前,否則我們肯定盡量希望 \(i+1\) 放置的位置盡可能靠后,這個將每個串出現的位置壓入一個 set 然后在 setupper_bound 即可找到,這樣最大值部分就可以在 \(|S|·n!·2^{n-1}\) 的時間內解決。

接下來考慮如何求所有字符串覆蓋的位置的並的最小值,首先我們踢掉 \(n\) 個子串中所有包含於另一個子串的子串,因為由於我們求的是最小值,我們肯定會將這樣的子串覆蓋在包含它的那個子串的位置上最優,此時這樣的字符串不會對答案產生任何影響。這樣我們可以設計出一個 DP:\(dp_{i,j}\) 表示目前選擇了 \(j\) 中的字符串,並且目前選擇的字串中,右端點最大的字符串的出現位置的右端點為 \(i\),覆蓋的位置的並的大小的最小值,轉移就枚舉右端點為 \(j\) 的字符串是啥,設為 \(x\),有兩種轉移:

  • \(dp_{i,j}\leftarrow dp_{k,j-\{x\}}+len_x\),其中 \(len_x\) 為子串 \(x\) 的長度,\(k<i-len_x\)
  • \(dp_{i,j}\leftarrow dp_{k,j-\{x\}}+i-k\),其中 \(i-len_x\le k<i\)

乍一看這個轉移式,你可能會以為需要用線段樹等結構維護轉移,實則不用。可以發現對於上面那種轉移,必然有 \(i-k>len_x\),因此我們把下面那種轉移的下界改成 \(0\) 依然可以計算得到正確的 DP 值,這樣轉移就變成求一段前綴 \(\min\) 的形式,維護兩個數組 \(mn1_{i,j}\) 表示 \(\min_{k\le i}dp_{k,j}\)\(mn2_{i,j}\) 表示 \(\min_{k\le i}dp_{k,j}-k\),這樣可以 \(\mathcal O(1)\) 轉移,於是我們就在 \(\mathcal O(|S|·2^{n})\) 的時間內求出了最小值。

44. CF1521E Nastia and a Beautiful Matrix

一道其實還算容易的構造題(?)

首先不難發現對於一個 \(n\times n\) 的矩陣,按照如下方式填能夠最大化有值的位置個數:

\[\begin{bmatrix} *&*&*&*&*&\cdots\\ *&0&*&0&*&\cdots\\ *&*&*&*&*&\cdots\\ *&0&*&0&*&\cdots\\ *&*&*&*&*&\cdots \end{bmatrix} \]

其中 \(*\) 表示一個非零值。由此我們可以得到,對於一個 \(n\times n\) 的矩陣,其中最多可以有 \(n^2-\lfloor\dfrac{n}{2}\rfloor^2\) 個非零元素。

但是,\(n^2-\lfloor\dfrac{n}{2}\rfloor^2\ge m\) 並不一定是我們能夠將 \(a_1\)\(1\)\(a_2\)\(2\)\(a_3\)\(3\)、……、\(a_k\)\(k\) 填入矩陣的充分條件,顯然,如果 \(a_1=n^2-\lfloor\dfrac{n}{2}\rfloor^2\),且 \(n\ge 2\),那么我們全填 \(1\) 肯定不符合條件 \(2\)。容易發現,我們最多在這 \(n^2-\lfloor\dfrac{n}{2}\rfloor^2\) 個非零位置中,填入 \(n·\lceil\dfrac{n}{2}\rceil\) 個同種元素,這個可以通過對矩陣進行黑白染色 + 抽屜原理證明,構造如下:

\[\begin{bmatrix} 1&1&1&1&1&\cdots\\ *&0&*&0&*&\cdots\\ 1&1&1&1&1&\cdots\\ *&0&*&0&*&\cdots\\ 1&1&1&1&1&\cdots\\ \end{bmatrix} \]

因此我們再記 \(mx=\max\limits_{i=1}^ka_i\),那么 \(n^2-\lfloor\dfrac{n}{2}\rfloor^2\ge m\)\(mx\le n·\lceil\dfrac{n}{2}\rceil\) 是否充分了呢?答案是肯定的。我們依次寫下 \(a_1\)\(1\)\(a_2\)\(2\),……,\(a_k\)\(k\),這樣可以得到一個長度為 \(m\) 的序列,不妨稱之為 \(b_1,b_2,\cdots,b_m\),那么我們按照如下方式填數:

  • \((1,2),(1,4),(1,6),\cdots,(3,2),(3,4),(3,6),\cdots,(5,2),(5,4),\cdots\)(即所有橫坐標為奇數,縱坐標為偶數的格子)中依次填下 \(b_1,b_2,\cdots\)
  • 填完了橫坐標為奇數,縱坐標為偶數的點后,再填橫縱坐標均為奇數的點,即 \((1,1),(1,3),(1,5),\cdots,(3,1),(3,3),\cdots\)
  • 如果這些點填完了還有剩余的數,那就再依次在 \((2,1),(2,3),(2,5),\cdots,(4,1),(4,3),\cdots\),也就是所有橫坐標為偶數,縱坐標為奇數的點中填數。

不難發現,在這樣的構造方式下,所有形如 \((2x+2,2y+1),(2x+1,2y+2)\)(也就是禁止填上相同的數的點對們)所填上的數在 \(b\) 序列中的距離都 \(\ge n·\lceil\dfrac{n}{2}\rceil\),而根據假設不存在 \(>n·\lceil\dfrac{n}{2}\rceil\)\(a_i\),因此這些點對中填上的數必然不同,因此我們的構造是合法的。

45. CF1073F Choosing Two Paths

一道細節略有點多的樹形 dp,不過思想還是很 simple 的(

首先感覺這個東西可以用類似於樹的直徑的方法搞,因此類比樹的直徑,我們設 \(f_i\) 表示 \(i\) 子樹內距離 \(i\) 最遠的點到 \(i\) 的距離。再設 \(dp_i\) 表示一個三元組,其中第一項為 \(i\) 子樹內選兩條以 \(i\) 為起點的路徑,它們重疊部分的最大值,第二項為 \(i\) 子樹內選兩條以 \(i\) 為起點的路徑,它們在重疊部分最長的前提下,覆蓋的總距離的最大值,第三項為在前兩項都取到最大值的前提下,重疊部分的下端點。那么顯然 \(f_i,dp_i\) 可以通過一遍 DFS 求出。

接下來考慮如何求解答案,不難發現最長路徑的重疊部分無非兩種,要么重疊部分的兩個端點是祖先關系,要么不是祖先關系,我們對它們分別討論,對於前者,我們枚舉深度較淺的那個端點 \(x\),換根 DP 一下求出每個點子樹外距離其最遠的點與其的距離,這樣可以用個 multiset 維護以 \(x\) 為根時,\(x\) 的每個子樹內的點與其距離的最大值。這樣可以更新答案。對於后者我們枚舉 LCA,不妨稱為 \(x\),那么相當於找到 \(dp\) 值最大的兩個兒子,multiset 維護即可。

時間復雜度 \(n\log n\)

46. CF1599A Weights

驚恐,某毛子出的比賽竟然在 CF 上有原題(大霧,指 ISIJ Cup T3

其實 CF 上這場比賽時間晚於 ISIJ2021 杯賽所以大概也沒有原題之說/yiw

首先觀察樣例沒有 \(-1\) 的情況因此我們猜測一定存在解,考慮如何構造之。我們先將 \(a\) 數組從小到大排個序,不妨假設 \(a_1<a_2<\cdots<a_n\),首先如果 LR 交替排列那我們肯定會依次將 \(a_1\) 放入左盤,\(a_2\) 放入右盤,\(a_3\) 放入左盤,依次類推,這樣每次放完以后,總重量的絕對值都小於當前擺下的最重的物品的重量,進而符合條件。考慮如果 \(s\) 不等於 \(LRLRLRL\cdots\) 如何處理,我們歸納構造,即從最后一次進行的操作開始往前推,如果最后兩次操作對應的字符相同,那我們就將 \(a_i\) 最小的物品放在最后一個,否則我們將 \(a_i\) 最大的物品放在最后,類似於一個雙端隊列的結構,然后再根據每次操作之后重量較大的是一邊決定物品放在哪一邊即可。

時間復雜度 \(\Theta(n)\)

47. CF1599J Bob's Beautiful Array

首先特判掉 \(n=2\)\(n=3\) 的情況,顯然 \(n=2\) 時只有 \(a_1=a_2\) 時才有解,解為 \(\{a_1,0\}\)\(n=3\) 時我們可列出一個三元一次方程組,把三個未知量解出來即可。

考慮 \(n\ge 4\) 時怎么做,顯然如果序列中有 \(\ge 1\) 個偶數,那么必定是存在解的,具體構造就是如果偶數個數 \(\ge 3\),那么找三個偶數 \(x,y,z\),令 \(a_1+a_2=x,a_2+a_3=y,a_3+a_1=z\),然后將剩下的數排成一列,不妨稱之為 \(b_1,b_2,b_3,\cdots,b_{n-3}\),然后令 \(a_{i}+a_{i+1}=b_{i-2},i\in[3,n-1]\) 即可,否則我們找到一個偶數 \(x\) 和兩個奇數 \(y,z\),然后重復上面的操作即可。

如果 \(a\) 數組中只有奇數怎么辦呢?設答案數組為 \(x\),那么我們考慮建立一張圖,如果 \(x_i+x_j\)\(a\) 序列中出現過,那么我們就連一條 \(i,j\) 之間的無向邊,不難發現這張圖中至少有 \(n\) 條邊,也就是說其中至少有一個環,我們考慮一個環意味着什么,顯然這個環中數的個數必須是偶數,而如果我們把這個環黑白染色,那么不難發現,黑色的點對應的 \(x_i\) 之和與白色的點對應的 \(x_i\) 之和相同,也就是說對於 \(a_i\) 全是奇數的情況,解存在的必要條件是存在兩個不相交的集合 \(S,T\),滿足 \(S\) 中所有元素之和與 \(T\) 相同。那這個條件是否充分呢?顯然是充分的,我們只要將剩余的數按照存在一個偶數的情況排列即可。

於是問題轉化為如何求解符合要求的兩個集合 \(S,T\),直接貌似背包復雜度似乎有些拉垮,不難發現一個性質:當 \(n\ge 28\) 時必然存在解,因為對於 \(n=28\) 的情況,有 \(\dbinom{28}{14}\approx 4\times 10^7\) 個大小為 \(14\) 的集合,而大小為 \(14\) 的集合中,不同的元素和只有 \(14·10^6<2\times 10^7\) 種,根據抽屜原理,必然存在兩個大小為 \(14\) 的集合,它們當中的元素之和相同,而如果我們扣掉這兩個集合公共的部分,剩余部分依然滿足元素之和相同,進而符合條件。

這樣一來我們的思路就很明顯了:取前 \(\min(n,28)\) 個元素,然后折半搜索前 \(\lfloor\dfrac{n}{2}\rfloor\) 個元素在 \(S\) 中的部分以及 \(T\) 中的部分,把它們的大小差和元素之和的差壓入一個 map 中,然后折半搜索后半部分的時候在左半部分的 map 中查找一下是否即可,時間復雜度大概是 \(3^{14}·14\),可以通過。

注意:此題略有些卡常,一開始使用 C++11 自帶的 unordered_map 被卡了,換成手寫的哈希表才得以通過/dk

48. CF871E Restore the Tree

首先非常明顯的一點是,根據每個點到關鍵點的距離我們可以確定每個關鍵點具體是什么——因為它就是到該關鍵點距離為 \(0\) 的點。當然如果這樣的點不唯一咱就直接輸出 \(-1\) 即可。在下文中為了方便起見我們稱這些關鍵點為 \(p_1,p_2,\cdots,p_k\)

我們不妨將樹根定在以 \(p_1\),這樣我們只要確定了每個點的父親,就可以確定整棵樹。下面我們的任務就是找到每個點的父親,一個 trivial 的 observation 是,對於 \(p_1,p_2,\cdots,p_k\) 構成的虛樹上的所有點,它們的父親是很容易確定的,因為對於一個 \(p_i\)\(p_1\to p_i\) 路徑上所有點組成的集合等於 \(\{x|d_{1,x}+d_{i,x}=d_{1,p_i}\}\),這個遍歷一遍即可求得,又顯然這些點的 \(d_{1,x}\) 互不相同,因此我們可以輕松獲取這些節點的父子關系——當然,如果這其中的父子關系出現沖突,我們需輸出 \(-1\)

接下來考慮如何欽定剩余的點,顯然對於每個不在虛樹上的點 \(x\),我們可以找到這個點到根路徑上深度最深的且在虛樹上的點 \(pt_x\),這個就枚舉所有關鍵點 \(i\),然后根據 \(d_{1,x}+d_{1,p_i}-2d_{1,\text{LCA}(p_i,x)}=d_{i,x}\) 得到它們 LCA 的深度,進而知道它們的 LCA 是誰,那么我們要求的 \(pt_x\) 就是所有 LCA 中深度最深的。

我們考慮把所有不在虛樹上的點 \(x\) 都存在 \(pt_x\)vector 里,然后遍歷虛樹上的每一個點,將其 vector 中的點按深度從小到大排序,然后考慮這些點的深度的每一個連續段,如果相鄰兩個連續段中點的深度相差超過 \(1\) 那么答案是 \(-1\),否則我們把這一連續段中的點掛在上一連續段中任意一個點下面即可。

時間復雜度 \(nk\log n\)

不過 u1s1 這道題的數據好像除了 test2 沒有 \(-1\) 的點,所以 \(-1\) 的情況你想咋判就咋判反正 test2 那么弱也不太可能 WA(大霧,/xyx

49. P7915 [CSP-S 2021] 回文

沒錯,這就是 CSP 時候把我送走的題(

綠題?綠題!綠題!!/fn/fn

我們考慮枚舉第一次操作是 L 還是 R,不妨設之為 \(c\),那么我們可以知道最后一次取走的是哪個數,如果我們把序列從這個數所在的位置劈開,顯然可以得到兩個雙端隊列,然后我們就維護四個指針在這兩個雙端隊列中貪心,即我們枚舉到第 \(i\) 位時,先盡量令 \(s_i=s_{2n+1-i}='\text{L}'\),看看是否可行,如果不可行就 LR,如果還不可行就 RL,如果還不可行就 RR,如果再不可行則說明第一次操作為 \(c\) 的情況不合法。如此貪心下去即可。

所以說,不少與雙端隊列/隊列取數的題都可以考慮貪心,只不過對於此題而言,只考慮眼前的利益,也就是讓每一步都最優是正確的,但是有些題目就不一定了,比如說……(劇透 ing)

時間復雜度 \(\Theta(Tn)\)

50. CF627F Island Puzzle

首先特判掉樹的情況,顯然此時移動方案是唯一的,簡單判斷一下即可。

環套樹的情況,我們不妨先以初始狀態中 \(0\) 所在的節點為根。可以發現假設環上的點在樹上的路徑為 \(u\to v\),那么不難發現繞着環交換的本質是將一個點單獨拎出來,然后剩余的點做一個輪換,因此我們考慮先求出將 \(0\) 的點由初始狀態中的位置換到目標狀態的位置時,得到的序列張什么樣,不妨設之為 \(\{c_n\}\),那么一個顯然的性質是,只有以下兩種情況時才有解:

  • \(c_i\ne b_i\) 的點組成一條祖先到后代的鏈
  • \(c_i\ne b_i\) 的點組成兩條祖先到后代的鏈,且這兩條鏈鏈頂節點的父親節點相同。

這個可以一遍 DFS 判斷,這樣我們可以知道添加的邊是什么,從而確定要輪換多少輪。那么有兩種輪換方法,要么 \(u\to v\),要么 \(v\to u\),分別計算一下取個 \(\min\) 即可,還有一部分是從初始節點到這個環再到終止節點的步數,顯然如果這個環中有節點在初始節點到終止節點的路徑上那肯定順路走過去最優,否則我們要么一開始走到環那么還原環上的點,要么到達終止節點以后還原環上的點,分別計算一下取個 \(\min\) 即可。

時間復雜度線性。


免責聲明!

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



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