JOI2020
代碼自己去LOJ看
要在日本多好,JOI Final比CSP-S簡單.jpg
只不過是長的領帶
顯然的貪心是刪掉某一個之后將兩個序列排序一一匹配。所以排序之后維護\(A\)序列的一段前綴匹配\(B\)序列長度相等的前綴的奇怪度和\(A\)序列的一段后綴匹配\(B\)序列長度相等的后綴的奇怪度就可以快速得到刪掉每一個位置之后的奇怪度。
JJOOII 2
設左端點為\(p\)的包含"J...JO...OI...I"、"O...OI...I"、"I...I"(省略號表示對應字符有\(K\)個)作為子序列的字符串的最小右端點為\(f_p,g_p,h_p\),按照\(h,g,f\)順序轉移,轉移時從后往前掃,用些東西維護當前位置向后遇到的第\(K\)個'J'、'O'、'I'的位置。
集郵比賽 3
暴力DP:設\(f_{i,j,k,0/1}\)表示在起點的逆時針方向走過\(i\)個收集點、順時針方向走過\(j\)個收集點、經過\(k\)個時刻、現在在起點逆時針方向的第\(i\)個收集點或順時針方向的第\(j\)個收集點,這樣的狀態下最多能收集多少郵票。轉移考慮走到起點順時針或逆時針方向上的下一個收集點。
\(k\)很大,不過可以發現\(f_{i,j,k,0/1}\)的值很小,同時在值相同的情況下\(k\)一定越小越優,所以改良一下:設\(f_{i,j,k,0/1}\)其中\(k\)表示收集了\(k\)張郵票,其余意義一致,其值表示滿足該條件情況下的最小用時,轉移同上。答案就是存在有意義的\(f_{i,j,k,0/1}\)的最大的\(k\)。
奧運公交
直接枚舉換邊暴力不太行,但是發現點數遠小於邊數。這啟發我們從枚舉點的思路出發考慮如何換邊。枚舉我們將要換的邊的起點\(u\),考慮\(1\)到\(n\)和\(n\)到\(1\)的路徑的可能情況。\(1\)到\(n\)和\(n\)到\(1\)實際上是一樣的,下面僅對\(1\)到\(n\)進行說明。不妨假設換的邊是\((u,v)\),那么有以下若干情況:
- 從\(1\)到\(n\)根本沒經過\(u\);
- 從\(1\)不經過\((v,u)\)邊走到\(u\),然后從\(u\)走到\(n\);
- 從\(1\)經過\((v,u)\)走到\(u\),然后從\(u\)走到\(n\)。
為了計算以上信息,我們需要求出:
- \(1\)到\(n\)不經過\(u\)的最短路;
- \(1\)到\(u\)的最短路;
- \(u\)到\(n\)不經過\((u,v)\)邊的最短路。
看到第\(3\)個條件,好像要對於每一條邊跑最短路,但實際上沒有必要。我們可以在忽略所有\(u\)的出邊的情況下跑出\(1\)到其它點、其它點到\(n\)的最短路。
那么對於\(1\)情況可以直接計算;對於\(23\)情況可以求出到達\(u\)的最短距離,而對於從\(u\)到\(n\)不經過\((u,v)\)的最短路,相當於把其他\(u\)的出邊加上。可以通過最短路求出從\(u\)的每一條出邊出發到達\(n\)的最短距離並記錄最小值和次小值,如果翻轉了最小值對應的邊就用次小值貢獻,否則用最小值貢獻。
注意到圖中點數小而邊數大,可以使用\(O(n^2+m)\)的朴素Dijkstra,復雜度\(O(n^3+nm)\)。
火災
做出這個題的時候感覺自己太恐怖了(霧
首先將詢問變為前綴相減並離線,那么詢問變成了二元組\((P,T)\)表示對長度為\(P\)的前綴在\(T\)時刻進行詢問。
設\(S_{i,j}\)表示在\(i\)時刻\(j\)位置的火勢,考慮一個位置\(i\)的初始火勢\(S_i\)在\(R\)從\(0\)不斷變大時對序列的影響。它在\(1\)時刻會覆蓋\(i+1\)、\(2\)時刻會覆蓋\(i+2\)、……直到某一個時刻\(t\)覆蓋了\(i+t\)之后發現\(S_{t,i+t+1}>S_i\)然后貢獻停止。將時刻和覆蓋的位置看做一個點的橫縱坐標,它們恰好落在一條線段上。
如果轉成坐標系上的問題,覆蓋不那么好做,而求和是比較熟悉的數點問題似乎更好做。考慮差分,如果\(S_i\)在\(t\)時刻覆蓋了\(j\),那么認為\(S_{t,j}\)在\(t\)時刻增加\(S_i - S_{t-1,j}\)。那么位置\(i\)的貢獻就可以表示成若干個四元組\((i,L,R,\Delta)\)表示\(\forall j \in [L,R]\),\(S_{j-i,j} = S_{j-i-1,j} + \Delta\)。現在問題變為有若干條線段、每條線段對其經過的所有整點加上一個權值,多次詢問橫縱坐標小於等於某個值的所有點的權值的和。
考慮如何處理出四元組。從右往左維護\(S\)的遞增單調棧,那么加入\(S_i\)時會pop掉若干位置,\(i\)就會覆蓋這些位置所覆蓋的區間,且每段區間增量一致,可以得到等量四元組。這樣可以得知四元組數量是\(O(n)\)的。注意到\(S_i\)覆蓋的區間連續,所以可以對\(i\)位置的所有四元組的\(\Delta\)差分,並將左端點全部設為\(i+1\),這和原來是等價的。這樣我們可以記修改為三元組\((i,R,\Delta)\),對應上述四元組\((i,i+1,R,\Delta)\)。
當然直接數點還是不行,不妨考慮修改\((i,R,\Delta)\)對詢問\((P,T)\)的貢獻\((i < P)\),是\(\min\{R-i,P-i,T\} \times \Delta\)。接下來就是套路:將\([1,P]\)分為\([1,P-T-1]\)和\([P-T,P]\),前者滿足\(T<P-i\),后者滿足\(T \geq P-i\),所以這兩段區間內只需要考慮兩個值取\(\min\)。
對於\([1,P-T]\)區間貢獻是\(\min\{R-i,T\}\)。我們可以以\(R-i\)作為下標,用樹狀數組維護當前加入的所有直線的\((R-i) \times \Delta\)和\(\Delta\)的前綴和。對於一次詢問我們就查詢\(\leq T\)的位置的\((R-i) \times \Delta\)的和和\(>T\)的位置的\(\Delta\)和就可以算出貢獻;對於\([P-T+1,P]\)先轉換成前綴相減形式,然后同理維護若干個樹狀數組。
復雜度\(O(n \log n)\)但是一個詢問最多要拆成\(6\)個還要維護好幾個樹狀數組所以跑起來還是比較慢的。