P9527 [JOISC2022] 灑水器
很妙的題。
顯然要對祖先打標記。
如何打,\(d\) 很小,可以暴力跳,同時啟發我們設 \(f_{x,d}\) 表示 \(x\) 子樹內與 \(x\) 距離為 \(d\) 的標記,查詢時直接暴力跳 \(40\) 個祖先即可。
但是直接打標記會重複,被修改節點所在的那一條鏈會被修改多次。一頓分析發現其實就是在 \(f_{p,d-dis(p,x)}\) 和 \(f_{p,d-dis(p,x)-1}\) 處打標記。
反思:資料範圍不僅可以對時間最佳化有啟發,還可以壓進空間裡。
CF1295F Good Contest
顯然要離散化,將 \([a_i,b_i]\) 變成左閉右開的形式。
設 \(f_{i,j}\) 表示第 \(i\) 個數在第 \(j\) 個區間的方案數。列舉同在一個區間的連續段起點 \(k+1\),然後從 \(f_k\) 轉移過來。
P3665 [USACO17OPEN] Switch Grass P
發現最短路徑一定是一條邊,於是有一種列舉所有出邊的做法,會被菊花圖卡。
還有一個結論,這條邊一定在最小生成樹上。
是樹就好辦了,對每個父親開一棵線段樹,下標為顏色,然後維護每個孩子中的最小距離。
修改只會影響自己和父親的答案,只會修改父親的線段樹。在葉子處用 multiset 維護該種顏色所有距離,然後往上合併。
反思:對題目挖掘性質不要停留在粗淺的層面,需深度挖掘有利的性質。
P9520 [JOISC2022] 監獄
猜測:無解當且僅當某兩條線段互相夾住另一條線段的一個端點,或者一條線段完全包含另一條線段。
但是結論假掉了……(第二個樣例)。
判斷非法比較困難,考慮如何判斷合法。
如果合法,則存在一種先後順序使得他們可以順利到達。觀察得到可以若合法則存在一種方式使得每個人都不停頓地走到終點,因此我們只需思考先後順序。
有兩條性質:
- 如果 \(A\) 的起點在 \(B\) 的路徑上,那麼 \(A\) 必須先於 \(B\) 走。
- 如果 \(A\) 的終點在 \(B\) 的路徑上,那麼 \(B\) 必須先於 \(A\) 走。
於是我們 得到一種 \(\mathcal{O}(n^2)\) 做法,暴力建邊,然後拓撲排序判環。
最佳化就是樹剖之後線段樹最佳化建圖。
P9017 [USACO23JAN] Lights Off G
顯然要預處理。
Keys:初始開關的影響和變換開關的影響可以單獨計算,所以我們可以預處理某個狀態能否在 \(i\) 步內完成。
操作上界為 \(3n\)。把迴圈同構的拿出來可以最佳化到 \(\mathcal{O}(n2^n)\)。
反思:將初始和變化後的分開考慮。對於要預處理的題目,肯定得預處理初始狀態一樣的,這時將他們分開就很重要。
P9018 [USACO23JAN] Moo Route G
這種思維題是我不配做出來的。
首先要觀察到,\(a_i\) 全是偶數,因為最後要回到 \(x=0\)(當然我沒看見)。於是我們直接將 \(a_i\) 除以 \(2\)。
先從 \(n=2\) 開始入手,若 \(a_1>a_2\),顯然就是有 \(a_2\) 次是 \(0\to 2\to 0\),還有 \(a_1-a_2\) 次是 \(0\to 1\to 0\),所以方案數就是 \(\dbinom{a_1}{a_2}\)。
若 \(a_1<a_2\),稍微麻煩一點,因為此時你走到 \(2\) 後可以選擇回到 \(0\) 也可以不回。方案數是插板法 \(\dbinom{a_2-1}{a_1-1}\) 。
猜測這個可以推廣到任意情況,於是就透過了。
反思:對題目的觀察還是不夠,從簡單問題分析擴充到複雜情況的能力欠缺。
P1641 [SCOI2010] 生成字串
反思:打表技術不夠熟練,無限接近正解。
可以轉化成從 \((0,0)\to (n,m)\) 且不穿過直線 \(y=x\) 的方案數。
若 \(n=m\) 那就是卡特蘭數 \(\dfrac{\binom{n+m}{n}}{n+1}\),打個表發現不合法的方案數佔 \(\dfrac{m}{n+1}\),所以總方案數就是 \(\dfrac{n+1-m}{n+1}\dbinom{n+m}{m}\) 。
另一種理解方式是用折線圖,當接觸 \(y=-1\) 時翻折一下,就可以發現不合法方案數是 \(\binom{n+m}{n+1}\)。都是類似卡特蘭數的分析。
P9019 [USACO23JAN] Tractor Paths P
第一問可以倍增輕鬆求出。
如何做第二問,一直想著列舉關鍵點,但這樣肯定做不了。既然我們都倍增了,那我們列舉什麼時候脫離原有路徑的步數 \(i\),則答案為 \(\sum\limits_{i=1}^{ans-1}cnt(g_{b,ans-i},f_{a,i})\)。拆成前字尾之後倍增維護即可。時間複雜度 \(\mathcal{O}(n\log n)\)。
反思:思考時應從已知、已求出、前面用過的資訊入手。
[ARC180B] Improve Inversions
猜!
猜測答案是長度大於等於 \(k\) 的逆序對個數。
找出所有能換的位置,先換數值小的,再換大的。
怎麼換,對於一個 \(P_i\),找到能換的候選項集合 \(\{s_1,\dots,s_m\}\),然後先換大的再換小的。最後應該是 \(s_1\) 在 \(P_i\) 的位置上。
好的我對了。
[ARC180C] Subsequence and Prefix Sum
發現 \(0\) 有很大的影響。發現第一個選的數也有很大影響(但這種可以歸類為前面那種,因為初始值為 \(0\))。
一旦字首和出現了 \(0\),後面如果只選一個數,那麼跟不選沒區別。如果選不止一個數,那麼第一個數要是相同的選哪個都一樣。怎麼辦?
一開始想用最小表示法,但不會 。
發現自己智力不夠,思維混亂,我們只需再記錄 \(g_i\) 表示前面和為 \(i\) 且上一次為 \(0\) 的方案數。然後我們不用 \(f_{i-1,0}\) 轉移到 \(f_{i,a_i}\),這樣就避免了選一個數的情況。然後用 \(g_j\to f_{i,j+a_i}\),就計算上了不止選一個數的情況。每次迴圈後,\(g_{a_i}\leftarrow g_0\),\(g_0\leftarrow f_{i,0}\)。
反思:思維混亂,在計數題中是大忌。要學會歸納各種情況,減少複雜的分類討論,規約為簡單的問題。
P9189 [USACO23OPEN] Custodial Cleanup G
猜測是先把所有鑰匙收集,再按一定順序放置。
第一問可以用搜尋解決。
注意到一些結論:與 \(1\) 相連的點必須滿足 \(c_i=f_i\)。
猜測:把所有滿足 \(f_i=c_i\) 的點和 \(1\) 號點的 \(c_i\) 壓入桶裡。如果桶裡的顏色能夠進入任何一個不滿足 \(c_i=f_i\) 的點,那就可以。
好像不對。
看了題解感覺很sb。
發現第二問一種合法的方案,倒過來其實就是以 \(1\) 為起點的拿鑰匙方案,只是從拿 \(s\) 變成了拿 \(f\)。
於是也可以用類似方法解決。
P9192 [USACO23OPEN] Pareidolia P
稍微猜測是子序列自動機上動態 DP。
因為要求所有子串,設 \(sum\) 表示前一位匹配的方案數總和,考慮從 \(i-1\to i\):
- \(f_{i,j}=\max(f_{i-1,j-1}[s_i=t_j],f_{i-1,j})\)
- \(sum'= sum+f_{i-1,5}\)
- \(ans'=ans+sum'\)
線段樹維護矩陣即可。
CF280C Game on Tree
發現樹形 DP 是困難的。
設 \(f_i\) 表示 \(i\) 點被選中的次數,顯然 \(f_i=0/1\)。為什麼這樣設??因為和題目要求有關,也有人稱此為指示器隨機變數。
要求的就是 \(E(\sum f_i)=\sum E(f_i)\),而 \(E(f_i)=P_i\),即 \(i\) 點被選中的機率,如何求???
顯然一定要比它的祖先先選,所以機率是 \(\dfrac{1}{dep_i}\)。
P9131 [USACO23FEB] Problem Setting P
先考慮狀壓出每道題的狀態,狀態相同的單獨考慮。然後思考轉化判定條件:其實就是滿足前一道題是後一題的子集。
那我們設 \(f_s\) 表示最後一道是 \(s\) 狀態的題,列舉子集直接轉移,時間複雜度 \(\mathcal{O}(3^m)\)。
一個 Trick:將狀壓後的數折半,分成前後兩部分。
設 \(s_{i,j}\) 表示滿足 \(x\) 前 \(10\) 位是 \(i\),後 \(10\) 位是 \(j\) 子集的 \(f_x\) 的總和。那麼轉移的時候只需列舉前 \(10\) 位,修改 \(s\) 時只需列舉後 \(10\) 位。可以做到 \(\mathcal{O}(n2^{m/2})\)。
有一個大神 DP:考慮最佳化列舉子集,考慮每次加入一個元素,按 \(|S|\) 轉移,從集合 \(i\to i\cup \{s_1,s_2,\dots,s_k\}\) 有 \(k!\) 種方式。
設 \(f_{i,j}\) 表示現在走到集合 \(i\),用了 \(j\) 步的方案。
- 下一步走到的集合不選:\(f_{i\cup \{x\},j+1}\leftarrow f_{i,j}\)
- 下一步走到的集合選:\(f_{i\cup\{x\},0}\leftarrow f_{i,j}\times \dfrac{1}{(j+1)!}\times val_{i\cup \{x\}}\)
反思:轉化判定條件,配合一些 Trick 的使用。
P2467 [SDOI2010] 地精部落
一直想著插入 DP,後面發現好像處理不了邊界?
還是考慮從小到大加數。發現答案要麼是 M
字形,要麼是 W
字形,我們只需算一種就好了。
設 \(f_{i,j}\) 表示以 \(j\) 結尾的排列 \(1\sim i\),考慮轉移。
列舉上一次的結尾 \(k\),可以看作將 \(f_{i-1,k}\) 裡 \(\ge j\) 的數全部加一。於是就可以直接做。
反思:不要先入為主,陷入思維困境,及時從死衚衕裡跳出來。不過原方法的有些部分可以借鑑,比如這題可借鑑從排列的角度入手。
P9020 [USACO23JAN] Mana Collection P
很不錯的題。
首先還是得分析性質,發現可以在每個點一直等到某個時刻,然後再一次性跑到終點。
而且我們可以只在經過每個點的最後一次記錄。
考慮正難則反,算一條路徑的最小損失量,設其為 \(f\),則答案為 \(\sum\limits_{i\in \operatorname{path}} m_i\times t-f\)。這個是關於 \(t\) 的一次函式,可以李超線段樹維護。
設 \(f_{s,i}\) 表示集合為 \(s\),最後在 \(i\) 的最小損失量。這個可以費用提前計算:\(f_{s,i}\times sum_s\times dis_{i,j}\to f_{s\cup \{j\},j}\)。其中 \(dis_{i,j}\) 可以 floyd 直接求出。
有一個問題是可能會插入長度大於 \(t\) 的路徑,但這不影響,因為大於 \(t\) 的那一段一定是負貢獻。
反思:正難則反,挖掘出性質後設計合理的演算法解決問題。
P5336 [THUSC2016] 成績單
設 \(f_{l,r}\) 表示把 \([l,r]\) 全部取完的代價,然後我們發現轉移有點抽象,因為一個區間可能會被拆成很多個離散的段。因為資料範圍小,我們嘗試將狀態擴充套件一下,設 \(g_{l,r,mn,mx}\) 表示區間 \([l,r]\) 還剩下的數中最小值最大值分別是 \(mn,mx\) 的最小代價,那麼有轉移:
考慮 \(g_{l,r,mn,mx}\) 的轉移,列舉斷點 \(k\),那麼 \([l,k]\) 和 \([k+1,r]\) 這兩段要麼都剩下值域 \(\in[mn,mx]\) 的,要麼有一段全部取完,那麼轉移可以寫出來了。
離散化後時間複雜度 \(\mathcal{O}(n^5)\)。
反思:難以維護的東西就寫進狀態。
[ARC185D] Random Walk on Tree
一開始從 \(n=1\) 開始考慮,發現這不太好,應該從 \(m=1\) 考慮。
將 \(0\to i\to 0\) 設為一次往返,設 \(f_i\) 表示已經塗了 \(i\) 個點,到塗完 \(n\) 個點的期望往返次數,則 \(f_i=\dfrac{n}{n-i}+f_{i+1}\)。
答案即為 \(f_0\times 2-1\)。
現在考慮 \(m\ne 1\) 的情況。如何計算期望往返次數,可以看作 \(0\to (m-1)n+i\to 0\),將 \(0\to (m-1)n+i\) 的期望次數乘 \(2\)。關於這個的計算,可以使用 CF1823F 的做法。當然也有結論:往返次數為 \(2m^2\)。
所以答案就是 \(m=1\) 的答案乘上 \(m^2\)。
反思:從特殊到一般的過程中,特殊情況可以多樣化考慮,不能侷限於一種。
P2685 [TJOI2012] 橋
刪邊最短路模板題。
在最短路樹上考慮,記 \(T_1,T_n\) 分別表示從 \(1\) 出發和到達 \(n\) 的最短路樹。在 \(T_n\) 上找到一條 \(1\rightsquigarrow n\) 的最短路 \(P\)。
- 若 \(e\not\in P\),則最短路不變。
- 否則,列舉邊 \((u,v)\),若 \(T_1(1\rightsquigarrow u),T_n(v\rightsquigarrow n)\) 都不包含邊 \(e\),則 可以用 \(edge(T_1(1\rightsquigarrow u))+edge(u,v)+egde(T_n(v\rightsquigarrow n))\) 來更新 \(e\) 的刪邊最短路。
但這樣複雜度仍然不對。我們發現一條邊 \((u,v)\) 可能可以對很多個 \(e\) 產生貢獻。找到 \(T_1(1\rightsquigarrow u)\) 和 \(T_1(1\rightsquigarrow n)\) 的分界點,記為 \(L_u\),同理也有 \(R_u\)。那麼一條邊 \((u,v)\) 就有可能對 \(P\) 上面 \([L_u,R_v)\) 這個區間的邊產生貢獻,拿個線段樹維護一下 \(P\) 的刪邊最短路就好了。
時間複雜度 \(\mathcal{O}(n\log n)\)。
P11189 「KDOI-10」水杯降溫
真難吧。
考慮先做操作二再做操作一。這兩個操作都有很濃烈的對「差分」的暗示,於是我們設每個點的差分值表示自己減去父親。這樣操作一相當於單點加一。
可以只用操作一完成的局面當且僅當所有節點的差分值小於等於 \(0\),且根節點的點權小於等於 \(0\)。而兩個操作都無法使根節點以外的點差分值減少。所以若初始存在非根節點差分值大於 \(0\) 則無解。
現在就是要保證每個點差分值合法的情況下要求根節點點權最小。設 \(f_u\) 表示 \(u\) 子樹在滿足上述條件下最多能做幾次操作二。考慮從 \(f_v\) 推到 \(f_u\)。
發現每次操作二都會使除了 \(v\) 以外的其它 \(u\) 兒子的差分值 \(+1\),於是設 \(d_v=a_u-a_v\),我們轉化為下面的問題:
\(n\) 堆石子,每堆有 \(d_i\) 個,每次從 \(n-1\) 堆裡取一個,每堆最多 \(f_i\) 次不取,問最多取多少次。
可以看作是先全取再用找一堆放回去。二分答案 \(x\),需要滿足 \(\sum \max(0,x-d_i)\le x\),\(x-d_i\le f_i\)。
最後只需判斷 \(a_1-f_1\) 是否小於等於 \(0\) 即可。
反思:對這種涉及一些抽象操作的一定要嘗試簡化操作,這不僅依賴於套路經驗之談,也跟做題直覺有關係。比如這題帶有差分意向的暗示,就是解題的關鍵。
P11190 「KDOI-10」反迴文串
比較好想的構造題,主要是特殊性質提示的很明顯。
小於等於 \(n/2\) 的可以直接兩兩匹配。
否則,記 \(ta\) 表示出現次數最多的字母出現次數,\(tb=n-ta\),那麼我們就要讓 \(ta-tb+1\) 個出現次數最多的字母和一個剩下的字母匹配。
上述操作若都能匹配,剩下的要麼是奇數,要麼是偶數。對於奇數的就先拿出三個,剩下的再兩兩匹配就好了。
P9984 [USACO23DEC] A Graph Problem P
注意到給定過程其實是 Prim 演算法。
但 Prim 演算法我們不熟悉,於是我們從 Kruskal 演算法考慮。建出重構樹,我們發現一條連線了 \(u,v\) 兩個聯通塊的邊 \(e\),\(u\) 聯通塊的答案更新為原答案加上 \(e\) 再加上 \(v\) 裡的原答案。\(v\) 答案的更新同理。
線段樹已經足以解決。但是有更簡單的做法,就是帶權並查集。tag 合併順序從底向上,支援路徑壓縮。
P9130 [USACO23FEB] Hungry Cow P
感覺像是分治。
考慮動態開點線段樹維護每一天的乾草。
問題是這個東西怎麼算答案??每個區間可以往右邊區間貢獻一些東西,使得答案的計算沒有那麼容易。
考慮樓房重建線段樹,透過遞迴右兒子的方式來計算答案。
對於每個區間,我們維護區間答案 \(ans\),區間有草吃的天數 \(num\),區間對右邊區間的貢獻 \(s\),左兒子對右兒子的貢獻 \(son\)。
\(son\) 的求解,需要遞迴右兒子。設 \(\operatorname{query}(l,r,x)\) 表示當左邊區間對自己有 \(x\) 時,區間的答案。分遞迴左兒子和右兒子討論一下就好了。
反思:線段樹太好用了,學習 DS 的處理技巧。
P8907 [USACO22DEC] Making Friends P
可以感覺到是啟發式合併,但是不知道怎麼合併。
觀察到若我們刪除一個點之後暴力將與它相連的所有點兩兩之間連邊,那之後可能還存在刪點的情況,這是不優的。而因為刪除順序是 \(1\sim n\),於是我們直接欽定從編號最小的點連向其餘點就好了。
反思:對縮減邊數規模降低複雜度的運用不夠熟練。思考最佳化的時候可以從「如果暴力會帶來怎樣的不良影響」 的角度思考。
P8276 [USACO22OPEN] Hoof and Brain
太神了。
首先發現若存在一個點無出邊,則 B 贏。這可以透過對反圖拓撲排序實現。然後呢??
將原圖中出度為 \(0\) 的點去掉,建出新圖 。然後做一個大神染色:
- 初始時每個點 \(col_i=i\)。
- 若存在點 \(i\) 使得它出去的所有點顏色都相同,那麼令所有顏色為 \(col_i\) 的點都變成該顏色
- 重複上述步驟直到無法操作。
這時我們發現,若 \(col_x=col_y\) 則 B 贏,否則 H 贏!!!
為什麼?因為一個 \(u\) 點必然會走到 \(col_u\) 這個點,所以若 \(col_x=col_y\) 則 \(x,y\) 會在 \(col_x\) 這個點上堵死。
如何維護 \(col\) ?維護每個點出去的點的顏色種類集合,然後啟發式合併。
反思:大神染色法。
[ARC181D] Prefix Bubble Sort
發現要是在某一次排序過程中 \(x\) 被換到了 \(y\) 位置。那麼在此之後 \(y\) 都不會再發生改變了,因為前面沒有比它更大的數,而後面的數也不可能換到前面。
使用連結串列維護即可???有點難寫這東西。
其實我們可以換個角度,從被換到前面的那些數字入手。這些數每被往前滑動一次,逆序對就減少 \(1\)。而哪些數會被往前換呢??其實就是非字首最大值的位置。於是我們可以計算每一個位置的貢獻,然後就做完了。
反思:思維還是不夠靈活,容易陷入死衚衕走不出來,不肯換角度思考。
P8099 [USACO22JAN] Minimizing Haybales P
對於每個位置,在值域上二分出最小的能夠換到這裡的數,然後換到這裡,這個東西要維護一個區間最大值、最小值。
這tm是錯的,這東西沒有單調性。
不如考慮每個數往前換,這樣就好多了。
反思:一如既往的在子衚衕裡亂轉。
CF1632D New Year Concert
設 \(ans_i\) 表示長度為 \(i\) 的 \(a\) 字首答案。
首先有 \(ans_i=ans_{i-1}\),然後只需考慮是否刪掉這個 \(i\)。
有經典結論:固定右端點 \(r\) 的時候,它的字尾 \(\gcd\) 最多隻有 \(\log V\) 種。
於是我們可以求出所有以 \(i\) 結尾的字尾 \(\gcd\),然後判斷一下這個 \(\gcd\) 是否可能會等於一個字尾長度即可。如果存在這樣的 \(\gcd\),就把 \(a_i\) 改為一個大質數,然後 \(ans_i\) 加一。
時間複雜度 \(\mathcal{O}(n\log V)\)。
P8100 [USACO22JAN] Counting Haybales P
首先要注意到差值 \(>1\) 的兩個元素不能改變相對位置,欽定相同元素的也不能交換。這樣就可以變成一個 DAG 拓撲序計數。
但是一般的 DAG 拓撲序計數是不能做的,繼續挖掘性質,發現奇數的拓撲序是唯一的,偶數也是,這樣只有兩條拓撲序固定的鏈相互連邊,這樣就能做了。
反思:DAG 拓撲序計數感覺是一種可以應用在某些計數題的好方法。這些計數題的元素之間存在一些先後順序的要求,這時就可以應用這種模型。當然如何挖掘「差值為 \(1\)」這個條件,它啟發我們思考這個東西是否能夠限制一些元素的相對順序,挖掘出這個條件後我們就可以使用上述模型。當然還要繼續挖掘性質,繼續利用這個條件聯想到奇偶性,很強!
CF2025E Card Game
首先題目的意思就是,同種花色內部比較,數值大的牌厲害。而花色 \(1\) 又可以擊敗其它任意花色。
我們發現除了 \(1\) 以外的不同花色間是不能比較的,所以在沒有 \(1\) 號牌的情況下,先手能贏肯定是對於任意一種花色,先手後手都各自選擇一半,設先手選了 \(a_1<a_2<\dots<a_{m/2}\),後手選了 \(b_1<b_2<\dots<b_{m/2}\),都有 \(a_i>b_i\)。將後手的選擇看成 \(+1\),先手看成 \(-1\),則對於同種花色的任意一種合法選擇方案,需要滿足任意的字首,字首和 \(s_i\ge 0\),這可以用卡特蘭數解決。具體的,可以看作是從 \((0,0)\) 走到 \((\frac{m}{2},\frac{m}{2})\) 且不穿過直線 \(y=x\),第一步必須向右走的方案數,為 \(\dfrac{\dbinom{m}{\frac{m}{2}}}{\frac{m}{2}+1}\)。
現在有了 \(1\) 號牌就沒那麼簡單了,我們考慮列舉用去打其它花色的牌的個數 \(t\),剩下 \(m-t\) 張 \(1\) 號牌內部互相鬥。那這時候其它牌就不一定要滿足上述條件,設 \(dp_{i,j}\) 表示 \(2\sim i\) 這些花色,用了 \(j\) 張花色 \(1\) 的合法方案數。列舉花色 \(i+1\) 用幾張 \(1\) 號牌,設為 \(k\),則 \(dp_{i,j}\times f(k)\to dp_{i+1,j+k}\)。其中 \(f(k)\) 表示在用 \(k\) 張一號牌的情況下,有多少種合法的分牌方式。
如何求 \(f(k)\)?首先仍然要滿足任意字首 \(s_i\ge 0\),但是現在先手只需要選出 \(\dfrac{m-k}{2}\) 張牌就好了,這可以看作從 \((0,0)\) 走到 \((m-\frac{m-k}{2},\frac{m-k}{2})\) ,且不穿過直線 \(y=x\),第一步必須向右走的方案數。設 \(X=m-\frac{m-k}{2},Y=\frac{m-k}{2}\),由 P1641 的理論,我們知道這個方案數是 \(\dfrac{X+1-Y}{X+1}\dbinom{X+Y}{X}\)。
現在只需要計算合法的花色 \(1\) 的分配方案,再乘上 \(dp_{n,t}\) 就好了。發現把合法的一種花色 \(1\) 選擇方案倒過來(整個序列翻轉之後,\(1\to -1\),\(-1\to 1\)),就是一種合法的其它花色選擇方案,所以也是 \(f(t)\)。
最終答案就是 \(\sum \limits_{t\in \operatorname{even}} dp_{n,t}\times f(t)\)。
CF2025F Choose Your Queries
題解說這是經典問題。
考慮圖論建模,將詢問的兩個點連無向邊,現在要做的就是給每條邊定向,並賦值。
我們發現,對於一組有公共點的邊 \(e_1,e_2\),設公共點為 \(v\),那麼我們可以讓兩條邊都指向 \(v\),給編號小的賦值 \(+1\),編號大的賦值 \(-1\),這樣可以保證任意時刻大於 \(0\) 並且操作影響抵消。
現在問題就變成了將無向圖劃分成最多的邊對,使得每個對的兩條邊都有公共點。這是經典問題:
我們在圖的 DFS 樹上考慮,設當前在 \(u\) 點。每次將 \(u\) 到兒子的邊以及回邊兩兩配對。可能會剩下一條,這時我們用 \(u\) 到父親的邊與其配對。最後最多在根剩下一條邊。
P11191 「KDOI-10」超級演出
設 \(L_i\) 表示讓 \(a_i\) 出場的最大 \(l\),\(R_i\) 表示下一個滿足 \(a_j=a_i\) 的 \(j\)。
對於一次詢問,就是問區間 \([l,r]\) 內 \(L_i\ge l,R_i>r\) 的 \(i\) 個數。拆成差分的形式就是一個 CDQ 分治。
\(R_i\) 是容易求的,怎麼求出 \(L_i\)?有一個樸素的轉移 \(L_i=\max L_j\),其中滿足存在 \(a_j\to a_i\) 的邊。發現這個東西其實可以根號分治。對於前驅結點 \(\le \sqrt{m}\) 的,可以直接暴力列舉前驅結點。\(>\sqrt{m}\) 的,這樣的點 \(\le \sqrt{m}\) 個,所以可以開一個陣列維護這些點的答案。每次求出一個新的 \(L_i\),列舉這些點看能否更新。
但是多一個 \(R_i\) 很難受,我覺得還是得去掉。其實因為我們只關心最後一個,我們直接在列舉到 \(i\) 的之後把 \(las_{a_i}\) 的值在樹狀陣列上去掉就好了。(PS:一直想帶個 \(R_i\) 的原因是我一開始以為只能用主席樹求那個玩意而主席樹不帶修……)
CF2030E MEXimize the Score
思考如何劃分,顯然分到一個集合內的數不能重複。
考慮往集合里加數,一開始所有集合的答案都是 \(0\)。現在加入了 \(t_0\) 個 \(0\),就有 \(t_0\) 個集合的答案加了 \(1\),再加入 \(t_1\) 個 \(1\),就有 \(\min(t_0,t_1)\) 個集合的答案加 \(1\)。可以發現,這個東西是一個字首 \(\min\)。所以一個序列的答案就是 \(\sum\limits_{i=0}^{n-1} \min\{t_0\dots t_i\}\)。
設 \(f_{i,j}\) 表示 \(\min\{t_0\dots t_i\}=j\),考慮轉移,若 \(i\) 這次要成為最小值,則 \(f_{i,j}=(\sum\limits_{k=j+1}^n f_{i-1,k})\dbinom{cnt_i}{j}\)。若 \(i\) 這次比最小值大,則 \(f_{i,j}=(\sum\limits_{k=j}^{cnt_i}\dbinom{cnt_i}{k})\times f_{i-1,j}\)。
最終答案是 \(f_{i,j}\times j\times \prod\limits_{k=i+1}^{n-1}2^k\)。
由於 \(\sum cnt_i=n\),時間複雜度 \(\mathcal{O}(n)\)。
CF2030F Orangutan Approved Subarrays
為啥沒做出來呢??
顯然線段相交就不行(包含可以),否則就可以。記 \(f_l\) 表示以 \(l\) 為左端點,右端點最遠能到哪。如果能處理出這個東西就可以 \(\mathcal{O}(1)\) 回答。
對於區間 \([i,nxt_i]\) 來說,找出所有 \(j\in(i,nxt_i)\),\(nxt_j>nxt_i\) 的 \(j\),取 \(nxt_j\) 的最小值。然後再讓 \(f_i\) 取一次字尾 \(\min\) 即可。將 \(nxt_i\) 從大到小排序即可使用線段樹維護。
反思:不善於將轉化後的模型套用經典的、通用的解法。就像這題,已經轉化成了線段相交模型,但是還是沒有去嘗試跟排序有關的做法。當然直接分析也無問題,但是太唐了。
P9970 [THUPC 2024 初賽] 套娃
一類和 \(\operatorname{mex}\) 有關的問題。
定義滿足 \(\operatorname{mex}(l,r)=x\) 的區間為 \(\operatorname{mex}_x\) 區間。對於一個 \(x-\operatorname{mex}\) 區間 \([l,r]\),如果不存在子區間也是 \(\operatorname{mex}_x\) 區間,則稱 \([l,r]\) 為「極小的 \(\operatorname{mex}\) 區間」。
有結論:極小的 \(\operatorname{mex}\) 區間只有 \(\mathcal{O}(n)\) 個。
考慮一個極小的 \(\operatorname{mex}_x\) 區間 \([l,r]\),假設 \(a_l>a_r\),則刪去 \(a_l\) 後,\(\operatorname{mex}\) 變為 \(a_l\)。不妨設 \([l+1,r]\) 對應的極小子區間為 \([L,R]\),因為 \(a_r\) 沒有在 \((l,r)\) 中出現,而又在 \([L,R]\) 中出現 ,所以 \(R=r\)。
這說明:\(\operatorname{mex}_x\) 區間必定為一個 \(\operatorname{mex}_t\) 區間向一端擴充套件到第一個數 \(t\) 得到。其中 \(x>t\)。
考慮從 \(x=0\to n-1\) 依次求出 \(\operatorname{mex}_x\) 的極小區間,對於每個 \(x\) 維護 \(\operatorname{mex}_x\) 極小區間的 vector
。時間複雜度是 \(\mathcal{O}(n\log n)\) 的。
接下來考慮所有對應 \(\operatorname{mex}_x\) 的極小子區間 \([l,r]\) 的大區間的形態。設 \(l\) 左邊第一個 \(x\) 在 \(L-1\),右邊第一個在 \(R+1\)。那麼大區間的形態就是左端點在 \([L,l]\),右端點在 \([r,R]\) 之間的所有區間。於是 \(\forall len\in[r-l+1,R-L+1]\),存在長度為 \(len\) 的區間 \(\operatorname{mex}=x\)。
於是問題就變成了有 \(n\) 個集合,每次區間加數,最後對所有集合求 \(\operatorname{mex}\)。差分一下,拿個 set
維護一下就好了。
P10218 [省選聯考 2024] 魔法手杖
首先考慮二分答案 \(mid\),需要判斷是否存在 \(x\),使得:
- \(\forall i,a_i+x\ge mid\)
- \(\sum\limits_{a_i\oplus x<mid}b_i\le m\)
第一個條件容易滿足,關鍵在第二個。
建出 Trie 樹,列舉 \(x\) 這一位填什麼,然後根據 \(mid\) 的大小判斷一下,時間複雜度 \(\mathcal{O}(nk^2)\)。
對於位運算,逐位確定答案是比二分答案更優的。
考慮 \(ans\) 這一位是否能為 \(1\),若 \(x=0\),則左兒子要 \(+\),此時要求 \(\sum\limits_{i\in lc} b_i\le t\),\(t\) 表示剩餘的體力,並且 \(\min\limits_{i\in lc} a_i +x\ge ans\),將 \(x\) 未確定的位都置為 \(1\),\(ans\) 未確定的位都置為 \(0\)(極端情況)。\(x=1\) 同理。
時間複雜度 \(\mathcal{O}(nk)\)。
P7831 [CCO2021] Travelling Merchant
考慮 DP,設 \(f_i\) 表示從 \(i\) 點出發的答案,則 \(f_u=\min\limits_{u\to v} \max(f_v-p,r)\)。
這樣做的問題在於無法精確的給出一些點的初始值。
那麼如何解決?我們需要繼續挖掘圖的性質,我們發現如果以 \(\max r_i\) 的資產出發一定能暢通無阻。而出度為 \(0\) 的點無解。
根據這個,我們可以從大到小考慮每一條邊,然後綜合拓撲排序與貪心設計一個演算法,具體見 P7831。
反思:腦筋急轉彎,多換角度思考。綜合各種演算法。
CF802L Send the Fool Further! (hard)
將這題和 CF1823F 混了。
那題求的是經過的期望次數,所以可以 \(f_u=\sum \dfrac{1}{\deg_v}f_v\)。
但是這題是求步數,顯然得倒推,於是你得 \(f_u=\sum \dfrac{1}{\deg_u}(f_v+w(u,v))\)。
這樣還是可以用套路去表出。
P5637 ckw的樹
有點太難了吧。
想要用常用套路,但是因為涉及到距離 \(\le 2\) 的點,所以得變成
的形式。
最初的式子還含有兒子、兒子的兒子、兄弟三種。前面兩種展開後都是簡單的,關鍵在於後面一種。
在上面那個式子的基礎上加上 \(D\sum \limits_{v\in bro(u)} f_v\)。可以用經典遞推套路,將 \(u\) 表示成只跟它的字尾兄弟有關,然後再倒推回去。那麼我們在 \(fa_u\) 處考慮它的所有兒子,就可以計算兄弟的貢獻。
程式碼抄的卷哥。