啥都想不到
A - Archeologists
考慮一個 naive dp:\(f_i(j)\) 表示第 \(i\) 個位置,深度為 \(j\) 的最大收益。那么:
然后這沒法直接優化,不過這個 \(f_i\) 其實是凸的。
證明可以用一個轉化:對位置 \(\{1, 2, \cdots, n-1, n\}\) 這些位置做線段覆蓋,線段左右端點必須為 \(1\sim n\) 的整點。一個點被覆蓋的次數為 \(c_i\),則答案為 \(\sum_{i}c_ip_i\)。附加條件:每個點被作為起點或重點至多一次。
用流表示選中一段區間——這樣使入邊和出邊容量為一即可控制這個附加條件。首先設 \(s_i=\sum_{j\le i} p_i\),考慮對於點 \(0, 1, 2, \cdots, n-1, n\),源匯點分別為 \(S,T\),如下建圖:
- \(i\to i+1\),容量無限,費用為 \(0\)。
- \(S\to i\),容量為一,費用為 \(-s_i\)。
- \(T\to i\),容量為一,費用為 \(s_i\)。
答案即為最大費用最大流,其凸性還是比較顯然的,那么 \(f_i\) 也是凸函數了。
如何維護 \(f_i\)?我們可以開一顆平衡樹,支持全局查最值(的位置),等差數列加。具體實現還有不少細節,我也沒寫過。\(O(n\log n)\) 已經可以通過了。
有趣的是,我們建好了費用流模型,使用模擬費用流的思想就能解決問題。考慮從右往左,用一個堆維護一個后綴的出邊。然后用當前位置的入邊去匹配一條最大的。由於不是每條邊都需要選擇,我們不妨每個位置入堆兩次,最后總共的貢獻中會有一次抵消(一個方案中 \(a\to b\) 和 \(b\to c\) 的值相當於 \(a\to c\))。這個做法好寫很多。其實就是帶悔貪心。
B - Reverse Game
只要想到逆序對這個關鍵切入點就勝利了。記逆序對數為 \(I\)。
考慮這些操作這么設置的本質,就是可以使 \(I\) 一次減少 \(1\) 或者 \(2\)(保證逆序對 \(\ge 0\))。如果要使 \(I\) 減一那么必然存在一個 \(\texttt{10}\) 子串,翻轉即可減一。如果 \(I>1\) 時需要減二,那也必然存在剩下三種子串之一。具體可以用反證法簡單證明。
\(O(n)\) 計算 \(I\),對於 \(I\in\{1, 2\}\) 是先手必勝,\(I=3\) 則后手必勝。根據必勝-必敗態定理易得 \(I\in \{4,5\}\) 是先手勝,\(I=6\) 后手……因此 \(I\bmod 3 = 0\) 時輸出 Bob
,否則輸出 Alice
。
D - Disk Sort
考慮一個思考方向:每次花費 \(\le 6\) 次操作排好一個顏色。
根據直覺,每次我們一定是選擇“移除目標顏色圓盤上的圓盤數盡可能少”的顏色,這樣我們清理上方比較方便。
對與一種顏色,設 \([a, b, c]\) 表示其三個位置的深度(由上到下深度依次為 \(0,1,2\))。注意到一個顯然的結論,就是一定存在一個 \([a, b, c]\) 使得 \(a+b+c\le 3\)。而除 \([1,1,1]\) 外的所有這樣的情況都可以通過不超過 \(6\) 次操作,得到一個新的排好序的柱子。
以上一共 \(5\) 中情況,都可以手模驗證。然而我們發現除去 \([1,1,1]\) 並沒有影響,因為總會存在一個顏色是滿足至少一個圓盤在頂上。
如果每次都找一個這樣的顏色,將其排序,一共需要 \(6(n-1)\) 次(最后一種顏色會在最后天然排好)。最后花費 \(3\) 次將最后一個柱子清空。
復雜度 \(O(n^2)\),實現非常有技巧性。如果不想寫長,可以考慮 \([a, b, c]\) 應滿足 \(a \le 0, b\le 1\)。這樣可以快速方便地找到可操作的顏色。我們目標明確地將目標圓盤都移到空柱子上,然后記錄一下除空柱子外的空位就能簡單地移除上方的障礙了。這樣還不用考慮兩個目標圓盤在同一個柱子上的情況。
參考實現(參考 hellomath):https://codeforces.com/gym/103102/submission/128966492
E - Divisible by 3
設 \(s(l,r)=\sum_{i=l}^r a_i\)。
考慮有 \(w(l,r) = w(l,k) + w(k+1,r) + (s_{k}-s_{l-1})\times (s_{r}-s_{k})\),這個東西很好拆,差分統計。
將左端點集合按前綴和以及前綴的 \(w\) 值按 \(\bmod 3\) 分類。然后就 \(O(n)\) 了。
F - Fence Job
考慮從合法的結果入手而不是操作,因為不同的操可能得到相同的結果。對於一個 \(h_i\),它可以通過操作“擴展”,從而對區間 \([l,r]\) 賦值,其中 \([l,r]\) 是極長的包含 \(i\) 的,滿足最小值為 \(h_i\) 的區間。
動態規划,定義 \(f(i,j)\) 為只使用 \(h_{1\sim i}\),構造一個長度為 \(j\) 的結果序列的方案數。考慮從 \(f(i, \cdot)\) 轉移到 \(f(i+1, \cdot)\)。設 \([l,r]\) 為其極大拓展區間,那么寫出轉移:
通過顯然的前綴和優化,這個式子已經可以 \(O(n^2)\) 算出了。實現時可以將第一維滾掉。
H - AND = OR
由於與操作不會變大,或操作也不會減小。那么我們定義一個指標,使得按照一個中間指標將區間中的數划分開,“大”的在一組,“小”的在另一組。大的用與運算,小的用或運算。然后直接判斷。
直接按數值大小作為指標划分是滿足條件的,然而不能直接枚舉,復雜度會出問題。而還有一個滿足條件的指標則是二進制中一的個數,相比之前的枚舉量只有 \(30\)。
考慮一個詢問 \([l,r]\),枚舉中間指標 \(k\),使得二進制中一的個數 \(<k\) 的在第一組,\(>k\) 的在第二組。而 \(=k\) 的,可以放在任意一邊。值得注意的是,如果 \(=k\) 中的數全部相等並且個數超過 \(1\),還可以分到兩邊。
使用線段樹離線處理即可(好像可以開 \(30\) 棵線段樹也行?)。復雜度 \(O(n\log n\log a)\),實現比較比較復雜,注意常數。
Update 2021/10/20:更新一個單 \(\log\) 分治做法:https://codeforces.com/blog/entry/90956?#comment-852344
I - Modulo Permutations
網上題解不清不楚,還是萬老爺靠譜。
切入點:對於任意一個數 \(x\),將它放在 \(1\) 或 \(2\) 的左側或右側都是合法的。而對於其他相鄰昂貴的兩數 \(a,b\),則 \(a>b\) 是必要(不充分)條件。
問題轉化為,將 \(3\sim n\) 分為兩組數 \(A,B\),使得 \(A,B\) 降序排序后滿足條件。一下以“1-段”和“2-段”簡稱。由於是降序,我們不妨從 \(n\) 考慮到 \(3\)。顯然有 naive 的 dp:\(f(x,i,j)\) 表示放置數字 \(x\sim n\),1-段末尾為 \(i\),2-段末尾為 \(j\) 的方案數。一個顯然的優化是,\(i,j\) 中必有一個 \(x\)。於是令 \(f(x,i)\) 為 \(x\sim n\) 中,\(x\) 在 1-段末尾,\(i\) 在 2-段末尾。那么有轉移:
第一個轉移比較平凡,\((x,x-1)\) 必然合法,相當於將數組復制了一遍。索性忽略它,直接略去第一維。而第二種轉移總數是調和級數級別的,直接枚舉 \(x-1\) 的倍數 \(+0,1,2\) 即可。復雜度 \(O(n\log n)\)。
J - One Piece
像這種 observation 題是真不會……
一個顯然的事情就是,如果對於一個點,存在另一個點的最遠距離小於這兩點間的距離,那概率就是 \(0\)。那么我們考慮先將這些點剔除,看似需要對每個點跑一遍 dfs,實際上只要對最遠距離最小的點操作一次就行了。
然后對於剩下的部分,考慮必然存在一對關鍵點形成的路徑為直徑。那么有,這個直徑的中點必然是上述那個最小點,記為 \(x\)。或兩個最小點間的邊,這種情況討論一下即可,暫且略過)。於是跑出每個點到 \(x\) 的距離,除了距離最大的那些點之外概率都是 \(1/2\)。
然后對於這些最大點,我們按其所屬 \(x\) 的子樹分類。可以發現,如果一類中點數較少,那么其中每個點分配到的概率就越大。所以具體算不清楚沒關系,不過可以確定的是必然 \(>1/2\)。
求解就先輸出最大點,輸出時按所屬類大小排序即可。然后輸出 \(1/2\) 的點,最后輸出剔除的點。
L - Neo-Robin Hood
考慮如果我們已經暫時選定了兩個集合 \(A, B\),代表我們的策略是“偷 \(A\) 買 \(B\)”(顯然要保證 \(|A|=|B|,A\cap B=\varnothing\))。這並不決定最終策略,於是調整。對於一個 \(x\in A\) 以及一個 \(y\in B\),如果“偷 \(x\) 買 \(y\)”比“偷 \(y\) 買 \(x\)” 更劣,那必然會交換他們。我們把條件寫出來:\(m_x-p_y<m_y-p_x\)。由於這個不等式的兩邊都涉及到了 \(x,y\),不好那么好操作。而經過移項,可得 \(m_x+p_x<m_y+p_y\)。我們設 \(val_x=m_x+p_x\) 作為排序的指標。
我們按 \(val\) 降序排序。考慮一個最終的策略 \(A, B\),必有 \(\max(A)<\min(B)\)。顯然一旦違反這個性質就可以做一些交換,小的編號換到 \(A\),大的換到 \(B\),可以發現新的策略必然優。
上面的性質促使我們將這個數組分為兩段,\([1: i]\) 以及 \([i+1:n]\),分別代表 \(A,B\) 的選取范圍。維護 \(A\) 使用大根堆,維護 \(B\) 使用小根堆。順序完成 \(1\sim n\) 中所有的 \(i\) 即可。不過似乎不太好同時控制兩邊的選取個數,當如果限定選 \(k\) 個卻簡單了。
二分答案。注意到答案 \(k\) 有單調性。如果選 \(f\) 個可行,那 \(f-1\) 必然可行。總復雜度 \(O(n\log^2 n)\)。
M - Mistake
考慮一個有趣的貪心:對於當前的 \(x\),將它加入到編號盡量小的當中去。具體的,對每個 \(i\in[1, n]\) 維護一個集合 \(S_i=\{1, 2, \cdots, k-1,k\}\),每次找到 \(S_x\) 中的最小值輸出並刪除。也就是說,輸入的圖白給了。
給個非常感性的說明,按照這樣的策略,越小的編號,其已經構造完的答案“越完善”。如果出鍋了實際上就是無解了。復雜度可以做到 \(O(nk+m)\)。