3.17(模擬賽)
100+45+30=175 rk12/54
A
考慮拆點跑二分圖最大匹配,左側連向右側的一條邊就相當於在原圖中選擇兩個有邊的點相鄰,然後就可以算出答案了。
注意特判只有一個孤立點且其他部分能夠完全匹配的情況,此時答案需要再 \(-1\)。時間複雜度 \(O(Tm\sqrt n)\)。
B
這種簡單題咋就差一步沒做出來呢?
發現所有工作最後的情況都可以規約到兩種上,一種是完全不刪,另一種是刪到正好到工作時間結束,這樣能把下一個也進行工作。容易歸納這樣是最優的,剩下的金幣直接從後往前刪就行了。
這樣就可以 dp 了,設 \(f_{i,j}\) 表示前 \(i\) 個工作,用了 \(j\) 個完整的區間到達下一個區間的起點的最小金幣數量。\(g_{i,j}\) 表示到達下一個區間恰好進入休息時刻的最小金幣數量。轉移預處理下一個結束在休息時間的工作,列舉這個工作的兩種狀態分別進行轉移。最後求答案的時候列舉每一個滿足 \(i\) 不存在下一個結束進入休息時間的工作 \(f_{i,j}\) 和 \(g_{i,j}\) 來更新答案。時間複雜度 \(O(Tn^2)\)。
賽時除了正確的兩個規約我還規約了第三類是全刪掉,這樣恰好就沒法 dp 了,唐。
C
首先有一個顯然的 \(O(n^2)\) dp。經過一些物理公式推導之後,對於 \(i\) 轉移到 \(j\)(\(i>j\))。對於 \(u_j^2+2h_j\geq v_i^2+2h_i\) 時,第 \(i\) 個人以最大速度扔出去,用 \(f_i-v_i+\sqrt {v_i^2+2h_i-2h_j}\) 更新 \(f_j\),否則第 \(j\) 個人用最大速度接住小球,用 \(f_i+u_j-\sqrt {u_j^2+2h_j-2h_i}\) 更新 \(f_j\)。
對於第二種轉移,可以看做一個以 \(u_j^2+2h_j\) 為自變數的函式 \(g(x)=a-\sqrt {b+x}\),分類條件對應定義域,這種透過平移得到的函式可以透過李超樹維護,李超樹每次插入線段並查詢最值,時間複雜度 \(O(n\log^2 n)\)。
對於第一種轉移,同樣看做一個 \(g(x)=a+\sqrt {b+x}\) 的函式形式。但是此時限制條件和定義域變成了兩個相對獨立的維度。所以需要使用線段樹套李超樹或者 cdq 分治,時間複雜度 \(O(n\log^3 n)\),常數小的 cdq 能過。
注意到定義域這個限制並沒用,第一類轉移所有插進來的查詢的時候,只要滿足限制條件,都是可以用來更新的。也就是所有查詢的自變數都在以前插入進來的函式的定義域以內。所以李超樹變成了全域性插入。但是此時還和全域性插入有一些區別,因為雖然查詢點在定義域內,但是並不是全域性都在定義域內。所以插入時會比較到一些無效節點。具體來說是對於一個點 \(x\),所有編號 \(\geq x\) 的函式是有效的。對於這種情況,我們需要對於每個李超樹節點,記錄編號 \(>mid\) 的最優函式,如果沒有再記錄編號 \(\leq mid\) 的函式。手玩一下發現這樣確實每個點都能取到最優答案。時間複雜度 \(O(n\log^2 n)\)。
3.18(題單)
AGC017C
智慧題。手玩一下,如果當前有 \(x\) 個球,\(x\) 節點上掛了 \(c_x\) 個球,那麼就連一條從 \(x\rightarrow x-c_x\) 的邊。如果從 \(n\) 到 \(1\) 聯通就有解。一次修改相當於把一個線段長度 \(-1\),一個線段長度 \(+1\),所以答案就是沒被覆蓋的部分的長度。時間複雜度 \(O(n+q)\)。
qoj3276
亂搞題。有一個結論是對於隨機序列,連續的正負相同的字首和個數是 \(O(\sqrt n)\) 級別的。如果正負改變顯然丟掉一半更優。所以可以暴力掃一下這 \(O(n\sqrt n)\) 個區間,將其中是字首最大值的元素加入考慮,不是字首最大值就說明有一個長度比他小且答案比他大。打表發現是字首最大值的個數是 \(O(n)\) 的。跑二維數點就能過 \(70\) 分,再隨便剪剪枝就能過 \(q=1\) 的那個包了。
qoj3047
這個經典套路竟然是第一次見到。建出第一棵樹的點分樹。對於點分樹上每個節點,考慮他點分樹上的子樹,在第二棵樹上建出這些點的虛樹,虛樹每個節點掛一個葉子表示在第一棵樹上距離分治中心的距離。然後對虛樹求出直徑之後對每個點求答案即可。時間複雜度 \(O(n\log^2 n)\)。
另一種做法是考慮每個節點在兩個點分樹上的一對祖先,對於每個節點數量是 \(O(\log^2 n)\) 的。與他距離最近的節點一定是在其中一對祖先上統計貢獻的。所以對每對祖先求出最小值和次小值,然後統計答案即可。時間複雜度 \(O(n\log^2 n)\)。為了卡空間需要先列舉第一棵樹上的分治中心,把空間複雜度降到 \(O(n\log n)\)。
gym102268D
擬陣題。用擬陣相關知識證明按照收益從高到低對區間進行排序,然後貪心依次嘗試插入就是最優的。
考慮判斷能否插入。考慮 Hall 定理,記 \(sum_i\) 表示前 \(i\) 個點的點權和,\(pre_i\) 表示前 \(i\) 個區間選擇的個數。那麼對於任意 \(i<j\),需要有 \(sum_{r_j}-sum_{l_i-1}\geq pre_j-pre_{i-1}\),移項之後用兩棵線段樹維護即可。每次加入一個區間就是在 \(pre\) 陣列上字尾加,需要維護區間最大最小值。時間複雜度 \(O(n\log n)\)。
3.19(USACO2024 Open Pt)
A
賽時只寫了 \(10\) 分的暴力,這種情況下儘量讓所有長度相同。剩下的不會,出了題解補。
T1 原來是簽到,那我不是得分與難度完全成反比。
建出 01 trie,發現充要條件是不能有祖先關係。對於一個節點\(x\) 上的東西,有兩種轉移方式,一種是對於葉子結點 \(y\),新建兩個分支,原來的節點挪到一個上,現在這個點挪到一個上,貢獻為 \(dep_y-dep_x+2\)。另一種轉移是對於只有一個兒子的節點 \(y\),放到他的另一個兒子位置,貢獻為 \(dep_y-dep_x+1\)。用小根堆來維護合法的轉移,啟發式合併即可,時間複雜度 \(O(|S|\log^2 n)\),常數很小,可以透過。
B
我怎麼調了三個小時才調出來啊?
首先試圖想了一些 \(\text{poly}\log\) 的做法,胡了一個 \(O(n\log^3 n)\) 的神秘做法 WA 但沒有 TLE,然後發現是個假做法。
考慮分塊。每 \(B\) 個一塊,設 \(L_i,R_i\) 為這一塊的左端點和右端點。對於每個塊,嘗試預處理出來每一個值經過這一塊之後變成什麼。發現如果樸素實現是 \(O(n^2)\) 的,所以需要發現一些性質。
設 \(mx_i=a_{L_i-1},mn_i=a_{R_i}\),首先觀察到除了最開始的 \(x\) 之外的情況 \(x\) 基本都是 \(\leq mx_i\) 的,又注意到如果 \(mx_i-mn_i+1<x<mn_i\),這一塊內的操作一定是加減交替出現的,所以這種情況就不需要預處理了,只需要記錄一個字首和陣列即可。那麼需要預處理的部分的個數就是 \(O(mx_i-mn_i)\) 級別的了。由於 \(a_i\) 單調不增,對於每個塊這個東西的和是 \(O(n)\) 級別的。所以預處理部分的時間複雜度就是 \(O(\frac{n^2}{B})\) 的。
對於查詢,先一直加或者減,直到下一個不再是加減,找到這個位置之後。散塊暴力整塊去查詢,就可以了,時間複雜度是 \(O(q(B+\frac{n}{B}))\) 的。
但是這樣會在 #6 #19 #22 三個點掛掉,事實上,進入塊的 \(x\) 並不一定是 \(\leq mx_i\) 的,如果前面出現了一個位置 \(p\) 滿足 \(a_p-\sum_{k=p+1}^{L_i-1} a_k>mx_i\),那麼來這個位置的就可以 \(>mx_i\)。我們將這種情況叫做特殊情況,其他叫做正常情況。那麼對於一個塊全都是特殊情況的話,這一個塊所有數的加減是一樣的。全是正常情況用上面的預處理資訊查詢。只有出現特殊情況向正常情況轉變的話,我們就暴力處理,但是這種情況的出現機率很小,只有在塊的交界處恰好出現了 \(a_i>2a_{i+1}\) 的情況才可能出現,並且最多出現 \(O(\log n)\) 次。最壞時間複雜度就是 \(O((n+q)\sqrt n\log n)\) 的。但是出題人並不知道塊長,也就無法把所有特殊情況都卡在交界處。所以只需要隨機擾動一下塊的邊界(其實不擾動出題人也不好卡),就是嚴格正確的 \(O((n+q)\sqrt n)\) 的複雜度了。
C
賽時設計了一個暴力的狀壓 dp,設 \(f_{i,s}\) 表示當前人在 \(i\) 個啟用點,\(s\) 集合內的段內有機器人的最小答案,知道了 \(f\) 就可以知道機器人的位置。
轉移列舉人下一步去哪,再列舉機器人轉動幾個單位之後啟用一個新機器人,需要一些細節的計算。時間複雜度 \(O(2^Rn^2R)\),期望得分 \(40\) 分。正解回頭補。
哈哈,最難的題是 T2,這下真資料結構學傻了。考慮相對運動,假裝機器人不會動,人和啟用點都會有一個順時針的基礎速度,然後人再自己決定一個速度。然後設 \(dp_{s,i}\) 表示 \(s\) 集合內有了機器人,人在第 \(i\) 個機器人的位置上的最小答案。轉移列舉下一個位置,然後二分找到第一個過來的啟用點,時間複雜度 \(O(2^RR^2\log n)\)。
發現可以先不二分,\(dp\) 陣列裡先記錄過來的時間(不需要等待的),容易發現這個越小等待後也越小,然後最後再二分找啟用點即可,時間複雜度 \(O(2^RR(R+\log n))\)。
3.20(題單)
CodeChef XYHUMOQ
\(|S|\leq 32\),考慮折半,對於前一半求出形如 \(101010\) 和 \(1010101\) 的有多少個,後一半求出形如 \(101010\) 和 \(0101010\) 的有多少個。打表發現最多有 \(1597\) 個。
然後記錄下來之後要滿足一個形如 \(a_1b_2+a_2b_1=m\) 的形式,對於每組 \(a_1,a_2\),再列舉 \(b_2\),\(b_2\) 只有 \(1597\) 種,然後求出 \(b_1\) 即可。時間複雜度不知道,可以過。
qoj5071
網格圖是二分圖,將所有左部點的顏色反轉,合法矩形等價於全是 \(B\) 或者全是 \(W\) 的矩形。考慮每個矩形的左上角,建立一個二分圖,左部圖表示全選 \(B\),右部圖表示全選 \(W\),將不能同時合法的點連一條邊,用全域性減去最小割就是答案,割掉表示就不讓他做出貢獻。
然後最小割求一下方案就行了,時間複雜度 \(O(Tnm\sqrt {nm})\),可以透過。
CF48F
傻逼卡常卡精度題。
卡精度可以用一個 long long
存證書,一個 long double
存小數部分。
卡常要注意 sort(a+1,a+m+1,[&](node x,node y){return x.v<y.v;});
的常數比 sort(a+1,a+m+1,cmp)
小一倍。
qoj3039
猜了個結論縮點之後 SCC 個數不會很多。所以縮點之後把所有 SCC 找出來,預處理出來兩兩之間可達性。每次詢問列舉所有 SCC 判斷是否在路徑上。時間複雜度不知道,可以過。
正解不會,回頭補。
ARC100F
正難則反,首先如果不考慮限制條件,那麼答案就是 \(k^{n-m}(n-m+1)\),考慮容斥掉不滿足限制條件的序列帶來的貢獻。對於 \(a\) 序列進行分類討論。
\(\text{Case 1:}\)
\(m\geq k\),且 \(a\) 序列中存在滿足限制的部分。
這種情況下需要容斥掉的數是 \(0\)。
\(\text{Case 2:}\)
\(m<k\),且 \(a\) 序列中兩兩不同。
考慮一個神仙的轉化,發現無論 \(a\) 序列長什麼樣都無所謂,所以我們需要統計的是所有不合法串中長度為 \(m\) 的滿足條件個數,最後再除以 \(A_k^m\) 即可。
設 \(f_{i,j}\) 表示填了 \(i\) 個數,當前最長的兩兩不同的字尾長度為 \(j\) 的方案數,\(g_{i,j}\) 表示出現過長度為 \(m\) 的次數。轉移分為兩種,填一個沒出現的數,\((k-j)f_{i,j}\rightarrow f_{i+1,j+1}\);或者填一個已經出現過的數,\(f_{i,j}\rightarrow f_{i+1,p}(p\leq j)\)。\(g\) 的轉移類似,同時如果 \(j\geq m\) 將 \(g\) 加上 \(f\) 即可。用簡單的字首和最佳化即可做到 \(O(nk)\)。
\(\text{Case 3:}\)
其他情況,即 \(a\) 中有相同元素。考慮列舉一個 \(a\) 序列的出現位置,那麼條件轉化為 \(a\) 序列兩邊不出現長度為 \(k\) 的互不相同的序列。所以可以對兩邊進行類似於 \(\text{Case 2}\) 的 dp,這時候只需要 dp 方案數了。注意到這裡初值不再是 \(0\),而是包含了 \(a\) 序列的一個前字尾。最後合併是卷積捲起來。時間複雜度 \(O(nk)\)。
3.22(模擬賽)
25+60+20=105 rk13/36
A
神秘題,被狠狠過河卒了。將未確定看做 \(2\),然後逐位暴搜。如果交換的兩位都是 \(2\),那麼初始 \(01\) 和 \(10\) 交換完是等價的。所以會變成兩種狀態 \(00\) 和 \(11\)。如果有一個是 \(2\),那麼交換完 \(2\) 的位置會發生變化。如果都不是 \(2\) 直接交換即可。
分析一下複雜度,每分兩個分支會減少兩個 \(2\),所以複雜度是 \(O(2^{\frac{n}{2}}m)\) 的,但是要寫遞迴不要寫 vector 實現的迭代,會被卡常。
B
其實是簡單題,但是衝了一場 A,沒來得及寫。
首先可以用線段樹求出來每個線段左右端點正上方和正下方的第一條線段,然後發現每個線段能到他的線段就是找到他一直向上跳覆蓋左右端點的線段,然後合併線段,直到有一個完全覆蓋當前線段的線段。答案就是這個類似於梯形的圖形中的線段數量。
考慮維護這個東西,先對於每個求出來那個完全覆蓋當前合併後線段的位置,發現就是能到他的裡面左邊界最靠左的一個上面的一條線段,拓撲排序一遍預處理出來。然後可以透過倍增跳到那個位置,同時用差分處理出來貢獻。對於處理貢獻,每次貢獻的是一個矩形內的線段,二維數點即可解決。然後用倍增預處理父親節點和到父親節點的權值,最後查詢的時候倍增跳到覆蓋他的線段即可。時間複雜度 \(O(n\log n)\)。
C
太困難了。
3.24(模擬賽)
100+55+10=165 rk8/34
A
容易觀察到最後形式是 \((a_i-x)2^x\),而 \(a_i-x\) 是偶數的情況都可以用更小的 \(a_i\) 和更大的 \(x\) 來表示。所以每個 \(a_i\) 能產生的貢獻就是 \(\frac{a_i}{2}\) 個數,所以可以用 \(O(\sqrt n)\) 的複雜度求出第一問。
設每個 \(a_i\) 出現了 \(c_i\) 次,那麼可以用 \(O(\log n)\) 的複雜度求出來 \(x\times 2^y\) 的排名,其中 \(x\) 是奇數。只需要列舉 \([y-\log n,y+\log n]\) 範圍內的計算這一組有多少在他前面,剩下的要麼全在要麼全不在。然後就可以二分找到第一行滿足 \(1\times 2^y\) 的排名在所求的數前面的,然後同理答案位置也只會在這周圍 \(O(\log n)\) 行內,對於每一行二分就可以做到 \(O(q\log^3 n)\),不知道能不能過。但是由於知道上一行的位置之後,下一行只需要檢驗 \(O(1)\) 個位置,所以複雜度為 \(O(\sqrt n+q\log^2 n)\),可以透過。
B
其實想到了類似的思路,但是沒有找到真正正確的方案就放棄了去想一些 cdq 狀物去了。最後 50min 狂拼 6k 暴力。
先考慮 \(k=1\) 的部分,可以用重鏈剖分的 dfs 序,將每條重鏈的鏈頂標記。然後對於非標記節點 dfn 序即可。然後再 dfs 一遍,遍歷到每個點的時候加入它所有標記的兒子。這樣的話,對於二操作,操作的是一個區間和 \(O(1)\) 個單點,三操作是標記和非標記對應的兩個區間,四操作是 \(O(\log n)\) 條重鏈和 \(O(\log n)\) 個單點。複雜度 \(O(n\log^2 n)\)。
對於 \(k\leq 10\) 的情況,類似的標記每條重鏈前 \(10\) 個節點。然後第二次 dfs 遍歷到每個點加入所有子樹內距離它為 \(10\) 的標記點。對於操作二,可以轉化為 \(O(k)\) 個 \(S_{u,k}\) 表示 \(u\) 子樹內到 \(u\) 距離為 \(k\) 的點集合。對於每個 \(S_{u,k}\),標記點一定是一個區間,非標記點只有一個,複雜度單次 \(O(k\log n)\)。對於三操作,前 \(10\) 層的標記節點用 \(S_{u,k}\) 來處理,其它層的標記節點一定是一個區間,非標記節點一定也是一個區間,複雜度單次 \(O(k\log n)\)。對於四操作,跳重鏈,對於鏈頂的 \(10\) 個標記節點暴力處理,其他的正常重鏈剖分,複雜度 \(O(k\log^2 n)\),總時間複雜度 \(O(qk\log^2 n)\),常數很小,可以透過。
C
有點神秘的 dp 題。有結論:合法矩形的充要條件是除去全零的行列之後,一定可以分成四塊,左上全 \(1\),右下全 \(0\),剩下兩部分也合法。充分性顯然,必要性就手玩一下,反正 OIer 不需要證明。
然後這樣就可以進行一個二維的區間 dp,設 \(f_{l1,r1,l2,r2}\) 表示這個矩形的答案,然後列舉劃分位置轉移,時間複雜度 \(O(n^6)\)。
發現轉移只需要從右下角 \(0\) 的階梯位置轉移,非階梯位置一定是不優秀的,所以轉移複雜度變成 \(O(n)\),總時間複雜度 \(O(n^5)\)。
再觀察一下,左下角矩形合法等價於下方兩個矩形的併合法,右上角矩形合法等價於右邊兩個矩形的併合法,因為右下角全是 \(0\)。所以狀態可以簡化為所有右下角矩形,為 \(O(n^2)\) 個,總複雜度為 \(O(n^3)\)。
3.26(題單)
ARC105F
條件等價於匯出子圖是一個聯通二分圖。先不考慮聯通的條件,如果只考慮二分圖,那麼可以列舉左部點,然後答案就是 \(2^{左部點與右部點連邊數量}\)。對於每一個集合計算這個東西,記為 \(g_s\),精細實現複雜度可做到 \(O(3^n)\)。
然後考慮處理聯通,容斥,設 \(f_s\) 表示 \(s\) 集合內聯通且是二分圖的方案數,那麼列舉編號最小的節點所在的集合 \(t\),有 \(f_s=g_s-\sum f_tg_{s\oplus t}\)。總時間複雜度為 \(O(3^n)\),可以透過。
qoj5070
先將網格圖左部圖的點顏色反轉,那麼就是不能用 \(2\times 2\) 同色聯通塊。考慮 bfs 一遍,推出一些可以推出來點的顏色,如果出現矛盾那麼無解。
這時候可能沒有全部染色完,但是不能繼續染色了。如果出現這種情況,容易發現,因為每一個都可以是任意顏色,所以將一個點隨機染色是不影響結果的。所以一旦出現這種情況,可以隨機染色一個點,然後用現在情況去推出一些點的顏色。重複這個過程直到出現矛盾或者全部染色完畢。時間複雜度 \(O(Tnm)\),可以透過。
gym102331H
差一點想出來,還是菜了。
首先顯然是凸的,可以 wqs 二分並單調佇列最佳化 dp 做到 \(O(nq\log n)\),平凡的。因為有區間操作,還可以比較容易的想到一個做法,用線段樹維護每個節點對應區間的 dp 值。設 \(dp_{0/1,0/1}\) 表示左邊是否貼邊界,右邊是否貼邊界的 dp 值。建樹時 pushup 就是合併兩個凸函式,用閔可夫斯基和實現,如果中間的兩個區間靠在一起下標要 \(-1\)。查詢的時候就閔可夫斯基和合並 \(O(\log n)\) 個區間的函式值,合併方式相同,這麼做時間複雜度分析出來是 \(O(nq)\) 的,但是由於帶著 \(4\) 倍大常數過不去,我獨立思考也就想到了這些。
上面兩個做法結合起來就是正解了。建出線段樹,用閔可夫斯基和得到每個區間的凸函式,這部分的複雜度是 \(O(n\log n)\) 的。然後查詢的時候,先進行 wqs 二分,二分一個斜率。然後去線段樹對應的 \(O(\log n)\) 個區間上二分出來這個斜率會截到凸函式的哪個位置,然後只需要合併這些區間截出來的 dp 值而不是整個凸函式。注意還是需要維護兩個表示是否貼右邊界的 dp 值來合併下一個區間。時間複雜度 \(O(n\log n+q\log^3 n)\),可以透過。