但是做的題太少了根本算不上長征。
寫這個是因為 NOIP2024 剩百日,這他媽是最後一次了,就讓我拿個一等吧,別無所求了。
把之前做過的題都重新總結一遍,怎麼說也都能吃透了。
P6880 JOI 2020 Final] オリンピックバス
給一個有向圖,經過邊有代價 \(C_i\),可以反轉某一條邊,代價為 \(D_i\)。問從 \(1\) 到 \(n\) 再從 \(n\) 到 \(1\) 且最多反轉一次邊的最小代價和。
暴力想法是列舉翻轉哪一條邊然後重跑最短路。考慮翻轉一條邊產生的影響,令 \(f(s,t)\) 為原圖上 \(s\) 到 \(t\) 的最短距離,翻轉一條邊之後 \(1\) 到 \(n\) 的最短路為 \(D1\),\(n\) 到 \(1\) 為 \(D2\)。
容易得出:\(D1=\min(f(1,n),f(1,v)+w+f(u,n)),D2=\min(f(n,1),f(n,v)+w+f(u,1))\)
然後需要知道一個性質:在圖 \(G\) 上構造根為 \(x\) 的最短路樹 \(T\),任意刪除一條不在 \(T\) 上的邊, \(x\) 到其他任意節點的距離不會發生變化。
那麼也就是說對於不在最短路樹上的邊,反轉這條邊後的 \(1,n\) 到其兩端點的最短路是不變的,也就不需要重新求最短路了。而在最短路樹內的邊最多隻有 \(n-1\) 條,那麼列舉到這些邊時重跑最短路是完全沒有問題的。
注意是稠密圖考慮使用不加堆最佳化的dij;有重邊所以判斷一條邊要記錄編號;在求起點不是 \(1\) 或 \(n\) 的最短路時可以考慮在反圖上以 \(1\) 或 \(n\) 為起點跑。
ABC264Ex Perfect Binary Tree
對於一棵樹動態加點,求當前以 \(1\) 為根的滿二叉樹個數。
計數題考慮 dp。首先滿二叉樹樹高最多 \(\log n\) ,所以只用考慮高度少於 \(\log n\) 的點。
設 \(dp_{x,dep}\) 表示以 \(x\) 為根,最大深度為 \(dep\) 的滿二叉樹個數。樸素轉移即在兩個層高為 \(dep-1\) 的滿二叉樹拼起來,即:\(dp[x][dep]=\sum\limits_{u<v,u,v\in son_x} dp[u][i-1]\times dp[v][i-1]\)
但因為是動態加點,所以這樣轉移複雜度會爆的。考慮將乘積式子拆開,根據完全平方公式可以化為:\(dp[x][dep]=\sum\limits_{u<v,u,v\in son_x} \frac{1}{2}((\sum\limits_{u\in son_x} dp[u][i-1])^2-(\sum\limits_{v\in son_x} dp[v][i-1])^2)\)
轉移過程中維護和與平方和即可 \(O(1)\) 修改變化量,複雜度 \(O(n\log n)\)
CF452F Permutation
給你一個 \(1\) 到 \(n\) 的排列,你需要判斷該排列內部是否存在一個 \(3\) 個元素的子序列(可以不連續),使得這個子序列是等差序列。
正解是線段樹維護雜湊,但是有奇妙性質:存在 \(3\) 個元素的等差序列時一定有其中點和左右兩端的距離不超過 \(12\)。當然這個值肯定是和 \(n\) 相關的,但那篇論文著實讓我看不出來。然後能過。
ABC329F Colored Ball
基礎的啟發式合併。我們對每個盒子開個 set 就行了,合併的時候就啟發式合併,小的合併到大的上保證複雜度。
CF1898D Absolute Beauty
考慮將 \((a_i,b_i)\) 看作是一段區間,我們想要在一次操作內增加儘量多的長度,考慮分討兩端線段的相交情況,最後得出結論:選擇最大的 \(l_i\) 和最小的 \(r_j\) 進行操作,可以使收益最大。
trick:類似於 \(|a_i-b_i|\) 的式子可以考慮轉化為區間來分討考慮。
P8386 & P10375
給定 \(n\),\(m\),求滿足以下限制的長度為 \(n\) 的序列數目:
-
每個元素在 \([1,m]\) 之間;
-
一次操作定義為刪除一個長度至少為 \(2\) 且區間兩端相等的區間,該序列需要在若干次操作內被刪空。
答案對 \(10^9+7\) 取模。
計數題,考慮dp。對於這種合法序列計數題,可以從在末尾新增一個數的情況入手,放在這個題中,發現對於一個序列 \(S\) 的某一項 \(x\),若其字首是合法的,則 \(S+x\) 也是合法的(原因顯然)。那麼這樣可以設出狀態:\(dp[i][j][0/1]\) 表示填了前 \(i\) 個數的序列合法/不合法,\(i+1\) 位置填已經出現過的 \(j\) 種數的方案數。
根據狀態設定,顯然適合用填表法,轉移要分討一下,分當前是否合法,填的數是已經出現的 \(j\) 種還是其他 \(m-j\) 種:
(dp[i+1][j][1]+=dp[i][j][0]*j%mod)%=mod;
(dp[i+1][j][0]+=dp[i][j][0]*(m-j)%mod)%=mod;
(dp[i+1][j][1]+=dp[i][j][1]*j%mod)%=mod;
(dp[i+1][j+1][0]+=dp[i][j][1]*(m-j)%mod)%=mod;
P11013 「ALFR Round 4」C 粉碎
首先考慮記 \(las_i\) 為 \(a_i\) 上一次出現的位置。手玩可以發現最優方案一定是刪除一段字首,最後剩下來的一定都是單牌。那麼也可以推斷出我們只需要找到最後一個可被刪掉的牌,並且這張牌一定是被匹配的一張牌。再思考一下,可以發現對於前 \(i\) 張牌,如果所有 \(las_i\) 前的所有 \(a_i\) 能被刪完,那麼 \([1,i]\) 就是能被刪完的。
那麼考慮設 \(dp[i]\) 表示是否能刪完 \([1,i-1]\),如果 \(dp[las[i]]=1\) 那麼 \([1,i]\) 就是能刪完的。考慮轉移,\(las_i\) 能被刪掉有兩種可能,一是與 \(las_{las_i}\) 匹配,二是被某一個 \(j\in(las_i,i)\) 和 \(las_j\) 匹配刪掉了,轉移綜合起來就是 \(dp_[i]|=dp_{las_j},j\in[las_i,i)\)。
這仍然是 \(O(n^2)\) 的。觀察式子,容易想到可以字首和最佳化,令 \(sum_i=sum_{i-1}+dp_{las_i}\) 就行,因為轉移也是從 \(las_i\) 處轉移的,轉移部分變成 \(dp_i=[sum_{las_i-1}<sum_{i-1}]\)。
P2446 SDOI2010 大陸爭霸
想法比較自然。會想到對於點 \(u\),其解鎖時間等於其前置節點的最大值 \(D\) 和自身的到達時間(不關心解鎖)的較大值。那麼可以直接跑一遍 dij 然後用拓撲排序的方式更新每個點的解鎖時間,很簡單。
然後你會發現只對了一個點,原因是你先直接跑 dij 可能會出現最短路上的點仍然未解鎖的情況,感性理解容易發現這顯然錯了,所以要在跑 dij 的同時進行拓撲排序對解鎖時間更新。注意更新解鎖時間要多開一個陣列。
UVA11987
直接無腦並查集是錯的。有個trick:考慮對每個集合建一個虛點,每次合併時就把要合併的點連到對應集合的虛點上,虛點始終保持不動,這樣子就對了。
[P1525 NOIP2010 提高組] 關押罪犯
帶權並查集,判斷關係時看兩點權值差的奇偶性就行。
[P6061 加油武漢] 疫情調查
網路流會不了一點。
P11022
容易發現當圖不聯通或是一棵樹時無解。考慮加入一條非樹邊形成一個環,一個簡單的想法是將某個點染成白色其它點染成黑色。但是這樣是能被hack掉的,考慮一條使得上述方案不合法的邊 \((u,v)\),如果要使其合法可以將包含 \(u,v\) 的一部分點全染成白色,這樣就合法了。
[P8817 CSP-S 2022] 假期計劃
首先 \(O(n^2)\) 預處理全源最短路方便後續操作,bfs即可。考慮暴力一點的想法,直接列舉要到達的點,但是資料明顯只允許暴力列舉兩個點的組合。容易發現,只需要列舉 \(B,C\) 點即可,因為 \(A,D\) 點都有一個距離 \(1\) 號點距離 \(\le k\) 的限制,所以在確定下來 \(B,C\) 之後就可以跟著確定 \(A,D\)。但是滿足限制的 \(A,D\) 可能很多,解決這個可以只考慮每個點能到達的最優點,但是因為選擇的點不能重複,所以要至少保留三個最優的點,可以用set或堆維護。然後列舉一下點的組合就做完了。注意 \(k\) 要加一和開 long long。
[P3537 POI2012] SZA-Cloakroom
資料範圍看錯了以為揹包過不了( 首先詢問離線下來是好想的,離線下來可以按 \(m\) 升序排序,同時對物品也按 \(a\) 升序排序。然後考慮怎麼滿足後兩個限制,如果沒有 \(b>m+s\) 的話就可以直接對 \(c\) 揹包求能否湊出 \(k\)。有個trick:考慮將設狀態為 \(dp[i]\) 表示物品的 \(c\) 之和為 \(i\) 的方案中最大的 \(b\) 最小值,只要這個儘量大的最小值 \(>m+s\) 那麼這個方案就是合法的,也就是有解。然後做完了。
[P8868 NOIP2022] 比賽
題意:給兩個 \(1\sim n\) 的排列 \(a,b\),定義一個區間 \([l,r]\) 的貢獻為 \(\max\limits_{l\le i,j\le r} a_i\times b_j\)。多次詢問,每次給定 \(l,r\) 求 \([l,r]\) 中所有子區間的貢獻之和,答案對 \(2^{64}\) 取模,\(1\le n,Q\le 2.5\times 10^5\)。可以離線。
求所有子區間的貢獻,一個簡單的思路是分治,那麼一個樸素的想法就是每次詢問都做一遍分治。分治過程中處理跨過中點的貢獻時可以考慮雙指標來計算貢獻,可以砍掉一個線段樹的老哥,複雜度 \(O(qn\log n)\),觀察資料可以過 52pts(多個老哥會少12pts,除非資料水),對於NOIP T4已經很不錯了。
如果要最佳化成正解,那麼肯定要一遍分治做完才行。自然的想法是將詢問離線下來,分治過程中提出包含當前區間的詢問,把貢獻給加到詢問上。