IOI 2020 集訓隊作業胡扯「1, 50」
IOI 2020 集訓隊作業胡扯「51, 100」(★)
IOI 2020 集訓隊作業胡扯「101, 150」
如果您點擊了某個超鏈接,但是並沒有發生任何變化,這意味着您可能需要在另外兩章節中尋找對應內容。
表格
綠的表示主要沒看題解,紅的表示主要看了題解。
2020-01-15
agc020_e
等價於計算有多少個編碼方式,解碼后能得到 \(S\) 的子集。
假設長度為 \(n\) 的字符串 \(s\) 的答案為 \(f(s)\),則可以列出兩種轉移方式:
-
\(f(s) =_+ f(s[1 : n - 1]) \times (1 + s[n])\)。
表示:編碼方式的最后一個字符為0
或1
,去掉這個字符后,前面的方案數即為 \(f(s[1 : n - 1])\)。
而當 \(s[n] = 0\) 時,最后的字符只能填0
,有 \(1\) 種方案;否則可以填0
或1
,有 \(2\) 種方案。 -
\(f(s) =_+ f(s[1 : n - li]) \times f(\bigcap_{j = 1}^{i} s[n - lj + 1 : n - l(j - 1)])\)(\(i \ge 2\),\(l \ge 1\),\(li \le n\))。
表示:編碼方式的最后一個字符為)
,也就是說最后一段是(
\(t\)x
\(i\))
,枚舉長度 \(l = |t|\) 和重復次數 \(i\)。
后面的 \(t\) 需要滿足解碼后是 \(s\) 中最后 \(i\) 段長度為 \(l\) 的子串的交的子集,也就是 \(\bigcap_{j = 1}^{i} s[n - lj + 1 : n - l(j - 1)]\) 的子集。
你可能會認為這樣子時間復雜度太大,但是題解告訴我們,記憶化搜索后,有用的狀態數是 \(\mathcal O (2^{|S| / 8} + {|S|}^3)\) 的。每個狀態可以花 \(\mathcal O (n^2)\) 的時間進行轉移,反正就是跑過了。
時間復雜度為 \(\mathcal O ({|S|}^2 2^{|S| / 8} + {|S|}^5)\),評測鏈接。
cf566C
注意到 \({|x|}^{1.5}\) 是下凸函數,也就是說每個位置都可以求出向最優解方向移動的傾向,也就是導數。
考慮點分樹,從根開始利用導數的正負確定應該往哪個子樹方向走,最多走 \(\log n\) 層。
不需要顯式建出點分樹。
時間復雜度為 \(\mathcal O (n \log n)\),評測鏈接。
2020-01-16
cf587F
這題和 cf547E 極其相似,那題是問 \(s_k\) 在 \(s_{l \sim r}\) 中的出現次數,這題是問 \(s_{l \sim r}\) 在 \(s_k\) 中的出現次數。
令 \(\displaystyle \sum_{i = 1}^{n} |s_i| = l\),有 \(l = \Omega (n)\)。
先建出 AC 自動機,然后考慮一下答案如何表示。
令 \(\mathrm{id}_{i, j}\) 為 \(s_i[1 : j]\) 在 AC 自動機上對應的節點。
特別地,\(\mathrm{id}_i = \mathrm{id}_{i, |s_i|}\) 為 \(s_i\) 在 AC 自動機上對應的節點。
則詢問 \((l, r, k)\) 的答案可以表示為:
令 fail 樹中的 \(\mathrm{id}_{l \sim r}\) 的子樹的權值都加上 \(1\)(重復的加多次)。
則答案為 \(\mathrm{id}_{k, 1 \sim |s_k|}\) 的權值和。
還以為和 cf547E 一樣能有簡單做法,結果想了半天都沒想到 \(\mathrm{polylog}\) 的做法,看了一下題解發現是根號的。
考慮根號分治,\(|s_k| \le T\) 的和 \(|s_k| > T\) 的詢問分開處理。
對於 \(|s_k| > T\) 的串,這樣的串不會超過 \(l / T\) 個,考慮對於每個串使用線性的時間處理:
先把 \(\mathrm{id}_{k, 1 \sim |s_k|}\) 的權值定為 \(1\),然后在 fail 樹上做一遍子樹和,求出每個點子樹中的權值和。
然后對於關於 \(s_k\) 的所有詢問,拆分左右端點並按升序排序,用一個指針掃過所有詢問端點,並用 \(\mathrm{id}_i\) 的權值累加答案。
這一部分的時間復雜度為 \(\mathcal O (l^2 / T)\)。
對於 \(|s_k| \le T\) 的串,每個詢問考慮用 \(\mathcal O (|s_k|)\) 的時間進行處理:
對於每個詢問拆分左右端點並按升序排序,用一個指針掃過所有詢問端點,每處理一個,就把 fail 樹上 \(\mathrm{id}_i\) 的子樹的權值都加上 \(1\)。
對於每個詢問 \(s_k\),查詢 \(\mathrm{id}_{k, 1 \sim |s_k|}\) 當前的權值並累加,就是該詢問的答案。
子樹加,單點查使用 DFS 序 + 分塊實現(\(B = \sqrt{l}\)),這一部分的時間復雜度為 \(\mathcal O (n \sqrt{l} + qT)\)。
令 \(T = \Theta (l / \sqrt{q})\) 可以取得最佳時間復雜度。
時間復雜度為 \(\mathcal O (n \sqrt{l} + q + l \sqrt{q})\),評測鏈接。
2020-01-27
cf571E
記集合 \(\{a, a b, a b^2, a b^3, \ldots \}\) 為 \(\langle a, b \rangle\),特別地,記 \(\{a\}\) 為 \(\langle a, 1 \rangle\)。
考慮合並 \(\langle a, b \rangle\) 和 \(\langle c, d \rangle\),形成新的集合,可以證明這個集合也可以表示成等比數列形式。
令所有 \(n\) 個 \(a, b\) 中涉及到的質數的集合為 \(P\),則可以把 \(a, b, c, d\) 表示為 \(|P|\) 維向量(第 \(i\) 個分量的大小為第 \(i\) 個質數在數值的質因數分解中的冪次)。
也就是要解 \(\vec{a} + k_1 \vec{b} = \vec{c} + k_2 \vec{d}\),其中 \(k_1, k_2\) 是非負整數。
考慮 \(\vec{b}\) 和 \(\vec{d}\) 是否為零向量,以及是否線性相關。
如果至少一個為零向量,可以直接判斷,如果不線性相關,可以解二元一次方程組,如果線性相關,需要解線性同余方程。
大分類討論即可。
時間復雜度為 \(\mathcal O (n^2 \omega(v) \log v)\),其中 \(v\) 是值域,\(\omega(n)\) 表示小於等於 \(n\) 的正整數的不同質因數個數的最大值,評測鏈接。
2020-01-28
cf590E
學習了一下偏序集上的最長反鏈求法。
令 \(l\) 為字符串長度之和。
先構造 AC 自動機,然后可以在 \(\mathcal O (l)\) 的時間內求出每個串在每個結束位置包含的最長的小串是哪一個。
注意這並不是全部的包含關系,所以還要用 Floyd 求出傳遞閉包,用 bitset 優化。
然后是偏序集上求最長反鏈(求方案),參考 [CTSC2008]祭祀river 的做法。
代碼中使用了 Dinic 求二分圖匹配。
時間復雜度為 \(\displaystyle \mathcal O \!\left( l + \frac{n^3}{w} + n^{2.5} \right)\),其中 \(w\) 為字長,評測鏈接。
2020-01-29
agc028_c
與其設置 \(x \to y\) 這條邊的權值為 \(\min(A_x, B_y)\),我們看成有兩條邊,權值分別為 \(A_x\) 和 \(B_y\)。這樣轉化后,答案仍然相同。
我們考慮某種最終答案,假設走了 \(x \to y\) 這條邊,
如果走的是權值為 \(A_x\) 的邊,我們把這條邊染紅色,
如果走的是權值為 \(B_y\) 的邊,我們把這條邊染藍色。
也就是說,紅色邊的邊權等於它的起點的 \(A_x\),藍色邊的邊權等於它的終點的 \(B_y\)。
我們考慮最終的答案形成的環,要么全是紅邊,要么全是藍邊,要么紅藍交替。
這不是廢話嗎?為什么要分三類?
這是因為只有紅藍交替,才能夠允許同時存在「入邊和出邊都是紅色的點」和「入邊和出邊都是藍色的點」。
也就是說,當且僅當紅藍交替時,才能任意選入邊和出邊的顏色,如果不是紅藍交替的,則顏色必須完全一樣。
那么我們先讓答案變成全選紅色和全選藍色的 \(\min\),也就是 \(\sum A_i\) 和 \(\sum b_i\) 的 \(\min\)。
然后考慮紅藍交替時的答案怎么計算:
因為紅藍交替時,必然會出現入邊為藍色,出邊為紅色的點。我們枚舉這樣的一個點 \(i\) 之后,把它的 \(A_i\) 和 \(B_i\) 都加進答案,只要在剩余的 \(2n - 2\) 個 \(A_j\) 和 \(B_j\) 中,選出最小的 \(n - 2\) 個,就一定能夠組成合法的答案。
把標號和權值一起記下來排序,就能得到每個點的 \(A_i\) 和 \(B_i\) 的排名,分類討論一下不難得到答案。
時間復雜度為 \(\mathcal O (n \log n)\),評測鏈接。
2020-01-30
arc097_f
我們的目標是把所有白點變黑。首先,特判掉沒有白點,或者白點只有 \(1\) 個的情況。分別輸出 \(0\) 和 \(1\)。
我們記 \({col}_i\) 為點 \(i\) 的顏色,如果點 \(i\) 為白色,則 \({col}_i = 1\),否則 \({col}_i = 0\)。
剩下的情況中,我們把包含所有白點的極小連通塊抽離出來(可以通過不斷刪除黑色葉子實現)。
顯然,這個連通塊形成了有 \(\ge 2\) 個點的一棵樹。令連通塊中的點數為 \(num\)。
不難發現,最優解中,貓一定不會踏出這個連通塊。
但是又必須經過連通塊內的每個點(因為必須經過連通塊里的所有葉子,連通塊中的所有葉子都是白點)。
那么接下來,我們只考慮這個連通塊,定義 \({deg}_i\) 為連通塊中點 \(i\) 的度數(不考慮原樹中的邊)。
又有結論:貓不會經過一條邊 \(\ge 3\) 次,也就是說只會經過 \(1\) 次或 \(2\) 次。
(這是因為多余的操作都可以簡化成“改變當前點的顏色”的操作,一定不會更劣)
我們先假設:貓必須回到起點。
可以發現這時貓的起點對答案已經沒有影響了。因為每條邊都會被正向反向分別經過恰好 \(1\) 次。
也就是說,先規划好了路線,計算這個路線對點顏色的影響。在這之后再“插入”改變當前點顏色的操作。
那么顯然,在這個情況下,如果 \({deg}_i\) 為奇數,則 \({col}_i\) 就會因為該點被到達了奇數次而發生改變,否則 \({col}_i\) 保持不變。
最終,答案就等於 \(2 \cdot (num - 1) + \sum {col}_i\),也就是 \(2\) 乘邊數,加上 \({col}_i = 1\) 的點數,這些點需要額外使用一次操作。
問題在於:貓不一定要回到起點。
假設貓從 \(x\) 出發,最終到達了 \(y\)。令 \(x\) 與 \(y\) 之間的邊數為 \(len\)。
則可以少走 \(len\) 條邊,也就是不用從 \(y\) 再返回 \(x\) 了。
但是少走的這 \(len\) 條邊,對 \(col\) 也有影響:
因為從 \(y\) 返回 \(x\) 的邊少走了,所以 \(x\) 到 \(y\) 路徑上的點(除了 \(y\) 本身)的 \(col\) 都會發生變化。
實際上恰好有 \(len\) 個點的 \(col\) 發生了變化。
如果 \(col\) 從 \(1\) 變成了 \(0\),可以少花一次操作。但是從 \(0\) 變成 \(1\) 的話,就要多花一次操作。
也就是說,平均算下來,如果原先的 \(col\) 是 \(1\),可以少花兩次操作;如果是 \(0\),則不虧不賺。
總的來說,就是這條路徑,經過的 \({col}_i = 1\) 的點要盡量多(但是不包含終點)。
一個觀察:葉子的 \(col\) 始終為 \(0\)(因為原先葉子的 \(col = 1\),但是葉子的 \(deg\) 也是 \(1\),所以抵消了)。
而這條路徑自然是越長越好,肯定會延伸到葉子,所以包不包含終點也沒有影響了。
樹形 DP 計算經過的 \({col}_i = 1\) 的點最多的路徑就行了。
假設最多經過 \(ans\) 個 \({col}_i = 1\) 的點,則最終答案為 \(2 \cdot (num - 1) + \sum {col}_i - 2 \cdot ans\)。
時間復雜度為 \(\mathcal O (n)\),評測鏈接。
agc030_d
因為 \(N\) 很小,考慮直接枚舉位置對 \(\langle i, j \rangle\)(\(1 \le i < j \le N\))以統計逆序對。
考慮一個概率 DP:令 \(f(i, j)\)(\(1 \le i, j \le N\))為當前時刻下,\(A_i > A_j\) 的概率。
(這里假設對於 \(Q\) 個操作,每個操作都以 \(1 / 2\) 的概率執行)
那么最終時刻下,滿足 \(i < j\) 的 \(f(i, j)\) 之和,再乘以 \(2^Q\) 就是答案(期望的線性性)。
按順序考慮每個時刻(操作),考慮新的 \(f(i, j)\) 和原先的比有什么變化。
可以發現只有 \(\mathcal O (N)\) 個位置會發生變化。具體地說,只有 \(i, j\) 有至少一個等於 \(X_i\) 或 \(Y_i\) 時才有可能發生變化。
暴力轉移即可。
時間復雜度為 \(\mathcal O (N (N + Q))\),評測鏈接。
arc093_e
考慮原圖的一棵生成樹 \(T\),邊權和為 \(S\)。
對於一條非樹邊 \(e\),定義 \(v(e)\) 為 \(W_e\) 減去「\(U_e, V_e\) 在 \(T\) 上的路徑上的最大邊權」。
也就是說,\(v(e)\) 表示用 \(e\) 替換 \(T\) 中的一條邊,形成新的生成樹的最小代價。顯然有 \(v(e) \ge 0\)。
假設染色方案已確定,如何計算滿足條件的最小生成樹?
- 如果 \(T\) 中的邊不同色,則 \(T\) 就是合法的最小生成樹,權值為 \(S\)。
- 否則 \(T\) 中的邊都是同一種顏色,取 \(v(e)\) 最小的異色的 \(e\),則合法的最小生成樹的權值為 \(S + v(e)\)。
- 如果不存在這樣的 \(e\)(所有邊全部同色),則不存在合法的生成樹。
那么答案就很顯然了,先把 \(X\) 減去 \(S\)。
如果 \(X < 0\),則無合法解,輸出 0
。
如果 \(X > 0\),則 \(T\) 必須同色,且 \(v(e) < X\) 的邊都必須染相同顏色,\(v(e) = X\) 的邊必須至少有一個染不同顏色。
如果 \(X = 0\),則是上面的答案的基礎上,再加上 \(T\) 不同色,其它邊任意選的方案數。
容斥一下答案就出來了。
時間復雜度為 \(\mathcal O (M \log M)\),評測鏈接。
2020-02-01
agc024_d
觀察樣例,再自己手造幾組數據,就可以發現,最終長成的樹必然是:
- 以一個點為中心的放射狀。
- 以一條邊為中心的放射狀(兩側對稱)。
更具體地說,也就是把中心點或中心邊「拎起來」,下面掛着的樹形態,滿足每個深度相同的子樹都完全一致。
而這時,答案就為樹的深度(假設中心點的深度為 \(1\),中心邊的兩端點深度為 \(1\))。
而葉子個數,就等於每一個深度的節點的,子節點個數的乘積(包括深度 \(1\),但不包括葉子所在的深度)。
那么我們枚舉中心點,或者中心邊,把原樹「拎起來」,原樹就變成了一個奇怪的形狀。
那么顯然我們需要補最少的點,對於每個深度,把子節點個數取 \(\max\) 再相乘,就得到最終的最少葉子個數了。
每個點和邊都枚舉一遍,取最優解。
時間復雜度為 \(\mathcal O (n^2)\),評測鏈接。
arc091_f
這題真的好簡單……
顯然我們求一下每堆石子的 SG 函數就好了。
我們打表找規律,當 \(K = 1\) 的時候,就是普通的 Nim。如果 \(K \ge 2\) 會怎么樣?
以 \(K = 4\) 為例:
不難發現規律:
然而直接這樣算有點慢,不難發現,如果按照 \(\displaystyle \left\lfloor \frac{n}{k} \right\rfloor\) 分段,則每一段內是循環的。
可以把第三行改寫成:\(\displaystyle \operatorname{SG}_k \!\left( n - \!\left\lfloor \frac{\displaystyle n - \!\left\lfloor \frac{n}{k} \right\rfloor\! \cdot (k - 1)}{\displaystyle \left\lfloor \frac{n}{k} \right\rfloor\! + 1} \right\rfloor\! \cdot \!\left( \left\lfloor \frac{n}{k} \right\rfloor\! + 1 \right) \right)\)。
這樣子計算,可以證明會在 \(\sqrt{n}\) 次內結束。
時間復雜度為 \(\mathcal O (N \sqrt{A})\),評測鏈接。
2020-02-02
agc035_c
當 \(N\) 是 \(2\) 的次冪時無解,這是因為 \(N\) 的最高位無法被異或得到。
否則一定有解,構造如下(令 \(m\) 為小於等於 \(N\) 的最大的 \(2\) 的次冪,\(k\) 為 \(N - m\)):
當 \(N\) 是偶數時才需要連 \((m+1) \leftrightarrow N\) 和 \(k \leftrightarrow N'\)。
時間復雜度為 \(\mathcal O (N)\),評測鏈接。
2020-02-03
cf603E
考慮給定了邊集后,如何判斷是否存在合法的選邊方案。
容易證明存在一種方案,當且僅當每個連通塊的大小都是偶數。
(考慮每個連通塊僅保留一棵生成樹,再在生成樹上自底向上選邊)
所以先把 \(n \bmod 2 \ne 0\) 的情況判掉(全部輸出 -1
)。
那么相當於每次我們可以嘗試不斷把權值最大的邊刪去,使得刪去后圖的每個連通塊大小仍為偶數。
加邊刪邊時,使用 LCT 維護最小生成樹即可。
判斷一條邊是否需要刪除,需要用能夠統計虛子樹信息的 LCT,這里虛子樹信息就是子樹大小。
為了方便考慮,代碼中在初始的時候就加上了 \(n / 2\) 條邊,第 \(i\) 條連接 \(2i - 1\) 和 \(2i\),權值為 \(\infty\)。
這樣做可以保證在一開始的時候每個連通塊大小都是偶數,省去了不必要的特判,如果算出來答案為 \(\infty\),就輸出 -1
。
時間復雜度為 \(\mathcal O (m \log m)\),評測鏈接。
2020-02-04
agc034_e
既然所有棋子最終到達了同一個點,我們先考慮枚舉這個點,記做 \(r\),以 \(r\) 為根建樹。
記 \(s_i\) 表示 \(i\) 子樹中的所有點 \(A_i\) 之和,也就是子樹中的棋子個數;
記 \(w_i\) 表示 \(i\) 子樹中的所有棋子到 \(i\) 的距離之和。
這樣,\(s_i\) 和 \(w_i\) 都可以很容易地計算。
(具體地說,\(\displaystyle w_u = \sum_{v \in \mathrm{sons}_u} w_v + s_v\))
考慮做題目中的操作會帶來的影響,假設操作的棋子分別位於 \(x, y\):
- \(x, y\) 為祖孫關系。這個操作對 \(r\) 本身,以及 \(r\) 的任意一個子樹方向的 \(w\) 值都不會產生影響(注意不是子樹,而是這個子樹對 \(w_r\) 產生的貢獻)。
- \(x, y\) 在 \(r\) 的不同子樹中。這個操作會使 \(r\) 的那兩個子樹方向的 \(w\) 值各減去 \(1\)。
- \(x, y\) 在 \(r\) 的同一個子樹中,但是不為祖孫關系。這個操作會使 \(r\) 的那一個子樹方向的 \(w\) 值減去 \(2\)。
可以發現:如果 \(w_r\) 為偶數,在所有子樹方向的貢獻中,最大的那一個,也不超過 \(w_r\) 的一半的話,就可以不斷通過 2 操作把某兩個子樹方向的貢獻減去 \(1\),最終使得 \(w_r\) 變成 \(0\)。也就意味着所有棋子都到達了 \(r\)。(具體方法是,每次都選擇當前貢獻最大的子樹中的一個棋子進行操作)
但是如果貢獻最大的那個子樹,它的貢獻超過了 \(w_r\) 的一半怎么辦呢?這時就需要在這個子樹中使用 3 操作以減小這個子樹的貢獻。可以發現這個貢獻減得越小越好。
這啟發我們定義 \(f_i\) 表示只操作 \(i\) 子樹中的棋子,能夠把 \(w_i\) 最小減少到多少。就是做操作后 \(w_i\) 的最小值。
這樣一來,只要 \(f_r = 0\),就意味着可以把棋子都聚集到 \(r\) 上,且根據上面的過程,恰好花費 \(w_r / 2\) 步。
(因為沒必要使用 1 操作,而 2, 3 操作都會讓 \(w_r\) 減去 \(2\))
我們考慮遞歸地計算 \(f_i\)。要求 \(f_u\) 時,考慮 \(u\) 的每個子節點 \(v\) 的 \(w_v\) 和 \(f_v\)。
同樣地,考慮對 \(w_u\) 貢獻最大的那個子樹 \(v\),我們使用 3 操作,讓它的 \(w_v\) 變成了 \(f_v\)。
這樣一來,若 \((f_v + s_v) \le w_u / 2\),則 \(f_u = w_u \bmod 2\),否則 \(f_u = (f_v + s_v) - (w_u - (w_v + s_v))\)。
這樣就可以在 \(\mathcal O (N)\) 的時間內計算最終聚集到點 \(r\) 的答案了。總時間復雜度為 \(\mathcal O (N^2)\),足以通過該題。
顯然這個式子是可以換根 DP 的,所以代碼中也就寫了,時間復雜度變為 \(\mathcal O (N)\)。
時間復雜度為 \(\mathcal O (N)\),評測鏈接。
agc026_d
去年 CSP 前,做過一個比賽,出題人搬了這題,我打了一整場比賽把它切掉了,其他題沒分(
PS:數據范圍改成了 \(1 \le N \le {10}^5\)。
注意:我的做法與題解的做法有較大出入。
我們首先考慮這樣的 DP:令 \(dp(i)\) 表示前 \(i\) 列已經染色,其他列還未染色的方案數。
但是這樣定義的狀態是沒法轉移的。
為什么?我們先考慮一下轉移的方式:
- 如果相鄰的兩個格子為同種顏色(
##
或##
或豎着排列的),則它們所在的 \(2 \times 2\) 區域中的顏色將被唯一確定。
即##
或
####
或它們旋轉 \({90}^{\circ}\) 的結果。
## - 如果相鄰的兩個格子的顏色不同(
##
或##
或豎着排列的),在不考慮其它限制的情況下,它們所在的 \(2 \times 2\) 區域中的顏色是有兩種方案的。
即##
或其旋轉 \({90}^{\circ}\) 的結果。
##
現在,考慮前 \(i - 1\) 列已經染色,第 \(i\) 列以及之后還未染色的情況。
那么第 \(i\) 列的染色情況,可以只由第 \(i - 1\) 列的染色情況確定。
下面舉幾個例子(假設第一列為第 \(i - 1\) 列,第二列為第 \(i\) 列):
?
,這個情況下第 \(i\) 列有 \(8\) 種染色方案:最底下 \(6\) 行 \(2\) 種,上面兩個格子 \(2 \times 2 = 4\) 種。
?
#?
#?
#?
#?
#?
#?
?
,這個情況下第 \(i\) 列有 \(4\) 種染色方案:最底下 \(6\) 行 \(1\) 種,上面兩個格子 \(2 \times 2 = 4\) 種。
?
#?
#?
#?
#?
#?
#?
#
,這個情況下第 \(i\) 列有 \(2\) 種染色方案。
#
#?
#?
#?
#?
#?
#?
#
,這個情況下第 \(i\) 列有 \(1\) 種染色方案。
#
#?
#?
#?
#?
#?
#?
可以發現,關鍵就在於第 \(i - 1\) 列的,最靠下的,上下相鄰兩個格子顏色相同的位置。
如果這個位置在第 \(i\) 列的范圍內,則第 \(i\) 列的最底下 \(\min(h_{i - 1}, h_i)\) 個格子的顏色就會被唯一確定,否則恰有兩種方案。
剩下 \(\max(h_i - h_{i - 1}, 0)\) 個格子可以任意染色。
可能可以考慮記狀態 \(dp(i, j)\) 表示前 \(i\) 列已經染色,且第 \(i\) 列最靠下的上下相鄰兩個格子顏色相同的位置為 \(j\)。
但是這樣狀態也太多了,也沒法做。
最后我們考慮記狀態 \(dp(i)\) 表示:前 \(i\) 列已經染色,且保證第 \(i\) 列任意兩個相鄰格子的顏色都不同的方案數。
也就是第 \(i\) 列顏色紅藍交錯的方案數。這樣令 \(h_{n + 1} = 1\),則 \(dp(n + 1) / 2\) 就是答案。
我們考慮轉移,如果 \(h_{i - 1} \le h_i\),也就是第 \(i\) 列變高了,則 \(dp(i) = 2 \cdot dp(i - 1)\)。
這是因為我們限制了第 \(i\) 列是紅藍交錯的,又因為 \(h_{i - 1} \le h_i\),所以第 \(i - 1\) 列也必然是紅藍交錯的,可以直接轉移。
但是如果 \(h_{i - 1} > h_i\) 怎么辦?這時限制第 \(i\) 列紅藍交錯,不能保證第 \(i - 1\) 列也是紅藍交錯的。
先小結一下:可以發現,如果第 \(x\) 列的最底下 \(w\) 個格子是紅藍交錯的,那么對於 \(y = x - 1\) 或 \(x + 1\),也就是 \(x\) 的相鄰列,可以推出第 \(y\) 列的最底下 \(\min(w, h_y)\) 個格子是紅藍交錯的。
這引出一個結論:如果第 \(x\) 列是紅藍交錯的,則第 \(y\) 列是紅藍交錯的充分條件是:對於 \(x \le i \le y\) 有 \(h_i \ge h_y\)。
換句話說,就是 \(h_y\) 是 \(x, y\) 之間(包含 \(x, y\))的 \(h\) 的最小值。
回到 DP 上,仍然是要轉移 \(dp(i)\),我們假設前一個一整列都是紅藍交錯的列為第 \(j\) 列。
則這個 \(j\) 要滿足 \(\displaystyle h_j < \min_{j < k < i} h_k\),且「\(h_j \ge h_i\) 或『\(h_j < h_i\) 且 \(\displaystyle \min_{j < k < i} > h_i\)』」。
這等價於 \(j\) 是前 \(i - 1\) 列單調棧中的元素(我們維護 \(h\) 值嚴格遞增的單調棧),且當加入 \(i\) 時 \(j\) 被彈棧或 \(j\) 為彈棧后的棧頂(但不能彈出 \(h\) 值恰好等於 \(h_i\) 的元素)。
根據單調棧的結論,總轉移數是 \(\mathcal O (N)\) 的,這是可以接受的。接下來要考慮轉移的系數。
我們首先考慮第一類轉移,也就是 \(j\) 為被彈棧的元素(\(h_j \ge h_i\))的轉移:
我們考慮上圖,\(j = 5\),\(i = 11\)。
\(j\) 到 \(i\) 之間的 \(h\) 值依次為 \(6, 10, 11, 8, 12, 10, 3\)。
我們已知第 \(j\) 列是紅藍交錯的,而之后的每一列都必須不是紅藍交錯的。
如果出現了類似圖二中的情況,也就是在“中間部分”(不包括 \(j\) 和 \(i\) 的部分)出現了相鄰兩列顏色沒有翻轉的話,就會導致“中間部分”出現一整列都是紅藍交錯的情況,不符合要求。
也就是說“中間部分”必須滿足:每一列的顏色都和上一列的不同,除了最初的那一列(第 \(j + 1\) 列)。
又因為第 \(i\) 列的顏色也可以選擇翻轉或不翻轉,所以這里總共貢獻了 \(2^2 = 4\) 的系數。
考慮圖三和圖四的上面的部分,因為不能讓第 \(8\) 列出現一整列都是紅藍交錯的情況,需要存在一行的顏色不翻轉,這里有 \(2\) 種情況。
而更上面未染色的部分,每一段紅色的線條都會產生 \(2\) 的貢獻(可以選擇翻轉或不翻轉)。
為什么有恰好 \(2\) 種情況呢?這是因為 \(h_8 - h_j = 8 - 6 = 2\)。
這一部分的總貢獻為 \(2^7 + 2^8\),實際上是一個等比數列的形式。
這個等比數列的首項為 \(2^{\mathrm{num1}}\),末項為 \(2^{\mathrm{num2} - 1}\)。總和就為 \(2^{\mathrm{num2}} - 2^{\mathrm{num1}}\)。
這里就有 \(\mathrm{num2} = 9\),以及 \(\mathrm{num1} = 7\)。
而 \(\mathrm{num1}, \mathrm{num2}\) 如何計算呢?
我們記 \(b_i\) 表示前 \(i\) 列的形如這樣的紅線個數。可以發現 \(\mathrm{num2} = b_{i - 1} - b_j\),而 \(\mathrm{num1} = \mathrm{num2} - (h_k - h_j)\)。
其中 \(k\) 就為上一個被彈棧的元素(這里 \(k = 8\)),也就是滿足 \(j < k\) 的 \(h_k\) 最小的元素之一。
綜上所述,\(j\) 對 \(i\) 產生的貢獻就為 \(4 (2^{\mathrm{num2}} - 2^{\mathrm{num1}})\) 倍的 \(dp(j)\)。
(特殊情況是 \(j = i - 1\),因為“中間部分”完全消失了,所以不能套用上面的推導,這時貢獻為 \(2\))
然后我們考慮第二類轉移,也就是 \(j\) 為彈棧后的棧頂,且上一個被彈棧的元素的 \(h\) 值不等於 \(h_i\):
仍然是 \(i = 11\) 的情況,此時 \(j = 2\)。
如圖二,同樣地我們不能允許出現在“中間部分”的相鄰兩列顏色不翻轉的情況。
特別地,如圖三,我們需要的紅藍交錯的高度不是 \(h_j\) 而是 \(h_i\),因為 \(h_i > h_j\)。
如圖四,可以發現此時顏色不翻轉的行,只有 \(1\) 種取值了,也就是 \(h_3 - h_i = 4 - 3 = 1\)。
而上面的部分仍然和前一種情況類似,我們可以求出此時的 \(\mathrm{num2} = b_{i - 1} - b_j - (h_i - h_j)\),而 \(\mathrm{num1} = \mathrm{num2} - (h_k - h_i)\)。
其中 \(k\) 的含義和前文相同,為上一個被彈棧的元素。
綜上所述,\(j\) 對 \(i\) 產生的貢獻就為 \(4 (2^{\mathrm{num2}} - 2^{\mathrm{num1}})\) 倍的 \(dp(j)\)。
(特殊情況是 \(j = i - 1\),因為“中間部分”完全消失了,所以不能套用上面的推導,這時貢獻為 \(2\))
然而其實我們漏掉了一種情況,要是這樣的 \(j\) 不存在呢?也就是不存在紅藍交錯的前一列該怎么辦?
其實這無關緊要,我們只要讓 \(h_0 = 1\),然后設 \(dp(0) = 1\) 就行了,不影響后續計算。
時間復雜度為 \(\mathcal O (N \log \mathrm{MOD})\),其中 \(\log \mathrm{MOD}\) 為快速冪復雜度,評測鏈接。
2020-02-05
arc103_d
令值域為 \(v\),本題中 \(v = {10}^9\)。
每次操作,你必須讓 \(x\) 坐標或 \(y\) 坐標增加或減少一個定值 \(d\)。
令一個點 \((x, y)\) 的奇偶性為 \((x + y) \bmod 2\),可以發現能夠操作到的點的奇偶性都相同,所以先把無解判掉。
好像沒有什么特別的構造方法。我們先考慮二進制拆分。
但是搞了半天之后,發現二進制拆分好像只能做到 \(2 (\lfloor \log_2 v \rfloor + 1)\) 次操作。
然后我們驚奇地發現,\(2 (\lfloor \log_3 v \rfloor + 2)\) 好像恰好就是 \(40\) 啊。
所以我們考慮把坐標表示成三進制數,注意這里三進制的系數,應該是 \(0, 1, -1\) 三種。
那么我們令 \(m = 40\),\(d_1 \sim d_m\) 分別為 \(1, 1, 3, 3, 9, 9, 27, 27, 81, 81, \ldots\)。
也就是對於每一個 \(0 \le i \le 19\),\(3^i\) 在 \(d\) 中出現兩次。
(如果所有點的奇偶性為 \(1\),則去掉一個 \(3^{19}\))
接下來構造解,每一位使用恰好兩個 \(3^i\):
我們從低位到高位考慮,假設考慮到了第 \(k\) 位。記 \(x_k, y_k\) 分別表示 \(x, y\) 坐標第 \(k\) 位的值。
- \(x_k = 0, y_k = 0\):
做RL
操作,也就是讓 \(x\) 減去 \(1\) 再加上 \(1\),也就是不變。 - \(x_k \ne 0, y_k \ne 0\):
做R/L
操作中的一個,讓 \(x_k\) 變成 \(0\);
做U/D
操作中的一個,讓 \(y_k\) 變成 \(0\)。 - \(x_k \ne 0, y_k = 0\):
如果 \(x_k = 1\),做LL
操作,讓 \(x_k\) 變成 \(3\);
如果 \(x_k = -1\),做RR
操作,讓 \(x_k\) 變成 \(-3\);
無論是哪種操作都需要進/借位,最后 \(x_k\) 還是變成了 \(0\)。 - \(x_k = 0, y_k \ne 0\):
類似上一種情況。
特別地,如果考慮到了第 \(k = 19\) 位:
- 點的奇偶性為 \(0\):只會出現上述情況中的 1, 2 兩種。
- 點的奇偶性為 \(1\):只剩一個 \(3^{19}\) 了,\(x_k, y_k\) 也必然只有一個非 \(0\),做
R/L/U/D
操作中的一個即可。
因為 \(\lfloor \log_3 v \rfloor = 18\),所以可以證明在執行上述操作時,只會影響到第 \(0 \sim 19\) 位。
時間復雜度為 \(\mathcal O (N \log_3 v)\),評測鏈接。
看了題解后發現我是睿智,可以用二進制的,而且只需要 \(32\) 次。
2020-02-06
cf553E
令 \(f(i, k)\) 為第 \(i\) 個點在 \(k\) 時刻,最佳策略下到達終點的代價期望值;類似定義 \(g(j, k)\) 表示第 \(j\) 條邊的代價期望值。
則 \(f\) 和 \(g\) 互相轉移,以 \(k\) 為階段可以發現都是從大往小轉移。最終答案就是 \(f(1, 0)\)。
固定 \(f(i, \ast)\) 和 \(g(j, \ast)\),轉移形式是一個卷積,用分治 FFT 優化即可。
一開始的邊界條件要先跑一下最短路。
時間復雜度為 \(\mathcal O (n^3 + m t \log^2 t)\),評測鏈接。
agc022_e
這道題挺神的,我嘗試用比較好理解的方式解釋一下:
我們考慮判斷一個已知的串是否合法。
首先一個顯然的事實:假設我們把串的某一位從 0 變成了 1,那么一定是變優了,反之一定是變劣了。
也就是說,單獨修改某一位的優劣性,是可以簡單判斷的。
接下來我們列舉一些操作的情況:
11a => 1
10a => a
01a => a
00a => 0
1ab => (a|b)
0ab => (a&b)
又有一結論:如果 \(S\) 形如 11...,那么一定合法,這是因為,只要把后面的部分縮起來,再縮 11a 得到 1 即可。
我們再考慮串形如 00... 時,因為遲早要對 00 進行操作,我們不妨直接考慮對 00 進行操作時:
假設串形如 00ab...,那么操作 00a 得到 0b...,操作 0ab 得到 0(a&b)...。
顯然前者不劣於后者,所以直接操作前者即可。也就是說 00a... == 0...。
考慮串形如 01... 時,同樣地,直接考慮對 01 進行操作時:
假設串形如 01ab...,那么操作 01a 得到 ab...,操作 1ab 得到 0(a|b)...。
當 a=0 或 b=1 時,前者不劣於后者。當 a=1 且 b=0 時,兩種操作分別得到 10... 和 01...。
到底是 10... 優還是 01... 優呢?這里我們先不作解答。
考慮串形如 10... 時:
假設串形如 10ab...,那么操作 10a 得到 ab...,操作 0ab 得到 1(a&b)...。
當 a=1 時,前者不劣於后者。當 a=0 且 b=0 時,后者不劣於前者。當 a=0 且 b=1 時,兩種操作分別得到 01... 和 10...。
又回到了比較 10... 和 01... 的問題上。
我們考慮 10xy... 和 01xy...:
- 如果 x=0,則前者可以得到 0y... 或 10...;而后者可以得到 0y...。
此時,前者不劣於后者。 - 如果 x=1,則前者可以得到 1y...;而后者可以得到 1y... 或 01...。
如果 y=1,前者不劣於后者。
如果 y=0,兩者都能得到 10...,而后者還可以得到 01...。
但是不能無限地往后接 10 循環,最終一定會變成 10a 或 01a,但是它們的結果確實是相同的,沒有孰優孰劣。
所以結論是 10... 比 01... 更優。
一個例子是:10001 和 01001,前者是合法的串,而后者不是。
那么我們構造如下轉移圖:
其中綠邊表示 \(0\) 的轉移,紅邊表示 \(1\) 的轉移,橙邊表示 \(0, 1\) 都是這個轉移。
然后在這個自動機上轉移即可。最終答案為 1 和 11 上的方案數之和。
時間復雜度為 \(\mathcal O (|S|)\),評測鏈接。
arc101_e
直接 DP 的話大概是 \(\mathcal O (N^3)\) 的,使用容斥原理:
要計算的就是 \(\displaystyle \sum_{S \subseteq E} {(-1)}^{|S|} f(S)\),其中 \(f(S)\) 表示強制不能覆蓋到 \(S\) 中的邊的方案數。
也就是把 \(S\) 內的邊都刪掉,原樹被分割成了若干連通塊,每個連通塊內部連線的方案數。
顯然一個大小為 \(n\) 的連通塊,任意連線的方案數為 \(1 \cdot 3 \cdot 5 \cdot \cdots \cdot (n - 1)\)(如果 \(n\) 是偶數,\(n\) 是奇數的話顯然沒有方案)。
那么設狀態 \(dp(i, j)\) 表示考慮 \(i\) 的子樹,割掉若干條邊,\(i\) 所在的連通塊大小為 \(j\),的貢獻總和(不算 \(i\) 所在連通塊的貢獻)。
轉移也是顯然的。
時間復雜度為 \(\mathcal O (N^2)\),評測鏈接。
arc101_f
首先,每個機器人只會從它旁邊的兩個出口離開。
對於旁邊只有一個出口的機器人,直接不管它就行,不會影響答案。
對於旁邊有兩個出口的機器人,我們只需要保存它到兩個出口之間的距離。
上述處理都可以通過雙指針來完成。
現在問題就變成了,給定 \(k\)(\(0 \le k \le N\))個機器人,第 \(i\) 機器人到它左邊和右邊的出口的距離分別為 \(x_i\) 和 \(y_i\)。
我們把每個機器人畫在坐標系中,第 \(i\) 個機器人的位置就是 \((x_i, y_i)\)。
可以發現,相當於我們操控兩條直線,初始時這兩條直線的位置分別為 \(x = 0\) 和 \(y = 0\),也就是在坐標軸上。
我們可以把豎線往右移動,把橫線往上移動。如果線碰到了一個點,這個點就被這條線吃掉,然后消失。
問點被線吃掉的,不同的方案數。
我們考慮這兩條線的交點形成的軌跡,可以發現,在軌跡上方的點是被豎線吃掉的,在軌跡下方的點是被橫線吃掉的。
那么我們考慮統計這條軌跡穿過這些點的方案數。限制是軌跡必須是增函數。
我們把坐標離散化一下,用樹狀數組優化 DP 就可以做了。
具體地說,我們把所有點按照橫坐標遞增排序。然后考慮某條豎線上的點如何轉移。
令 \(dp(i, j)\) 表示,考慮了橫坐標 \(\le i\) 的點了,並且軌跡下的點的縱坐標最大值為 \(j\) 的方案數。
則 \(dp(i, j)\) 可以轉移到 \(dp(i + 1, j)\) 和 \(dp(i + 1, y)\)(存在點 \((i + 1, y)\) 滿足 \(y > j\))。
用樹狀數組維護。
時間復雜度為 \(\mathcal O (M + N \log N)\),評測鏈接。
2020-02-07
arc103_f
假設滿足條件的樹為 \(T\),我們考慮 \(T\) 的一些性質。
首先 \(T\) 只有一個重心,因為如果有兩個,那么它們兩個的 \(D\) 值就應該相同,與題意矛盾。
顯然重心就是 \(D\) 值最小的那個點。
令 \(T\) 以重心為根,容易發現,任何一個非根節點的 \(D\) 值都大於它的雙親節點的 \(D\) 值。
我們選取 \(D\) 最大的那個點 \(u\),顯然它必須是葉子。
我們可以計算出它的雙親節點的 \(D\) 值應該恰好為 \(D_u - N + 2 \cdot \mathrm{siz}\),其中 \(\mathrm{siz}\) 為 \(u\) 的子樹大小(此時為 \(1\))。
那么就可以唯一確定它的雙親節點是哪一個。
然后把該點“刪去”,並讓它的雙親節點的 \(\mathrm{siz}\) 加上 \(1\)。
重復 \(n - 1\) 次這個過程。就可以確定出 \(T\) 的形態。
也就是說,滿足條件的 \(T\) 其實是唯一的。
這時我們再 DFS 檢查一下是否確實滿足條件即可。
時間復雜度為 \(\mathcal O (N \log N)\),評測鏈接。
agc020_d
首先我們可以得出:最短的連續段長度等於 \(\displaystyle \left\lceil \frac{\max\{A, B\}}{\min\{A, B\} + 1} \right\rceil\! = \!\left\lfloor \frac{A + B}{\min\{A, B\} + 1} \right\rfloor\),令這個值為 \(K\)。
觀察 \(A \ge B\) 的情況(留作練習,請讀者自行完成)(大霧)
可以發現,一組 \(A, B\) 的答案,就是當 \(A = (B + 1) K\) 時的答案(形如 \([B \cdot (K \cdot \texttt{"A"} + \texttt{"B"}) + K \cdot \texttt{"A"}]\)),
去掉靠后的恰好 \((B + 1) K - A\) 個 \(\texttt{"A"}\) 得到的,令這個值為 \(\mathrm{del}\)。
但是並不一定是去掉最后 \(\mathrm{del}\) 個 \(\texttt{"A"}\),考慮 \(A = 8, B = 6\) 的情況:\(\texttt{"AABAABAABABABB"}\)。
它就是 \(A = 14, B = 6\) 的情況:\(\texttt{"AABAABAABAABAABAABAA"}\) 去掉 \(6\) 個 \(\texttt{"A"}\) 得到的,但是不是最后 \(6\) 個。
這是因為如果去掉了最后 \(6\) 個,就會有 \(3\) 個 \(\texttt{"B"}\) 形成連續段,與「連續段長度不大於 \(2\)」沖突。
也就是說,貪心地去掉盡可能靠后的 \(\mathrm{del}\) 個 \(\texttt{"A"}\),但是不形成 \((K + 1) \cdot \texttt{"B"}\) 的連續段。
討論一下就可以得到結果了。
對於 \(A < B\) 的情況類似,是 \(B = (A + 1) K\) 時的答案(形如 \([A \cdot (K \cdot \texttt{"B"} + \texttt{"A"}) + K \cdot \texttt{"B"}]\)),
去掉盡可能靠前(不是靠后)的若干個 \(\texttt{"B"}\) 得到的,類似做就行了。
時間復雜度為 \(\mathcal O (Q (D - C + 1))\),評測鏈接。
2020-02-08
arc099_f
考慮記前綴和信息 \((\Lambda_i, \delta_i)\) 表示依次吃掉 \(1 \sim i\) 的所有字符后,得到的序列和指針 \(P\) 的位置。
那么兩信息的合並:\((\Lambda_1, \delta_1) \circ (\Lambda_2, \delta_2) = (\Lambda_1 + \Lambda_2 \gg \delta_1, \delta_1 + \delta_2)\)。
我們記 \(h_i\) 為 \(\displaystyle \sum_{p} \Lambda_i[p] \beta^p\)。
則有 \((h_1, \delta_1) \circ (h_2, \delta_2) = (h_1 + h_2 \beta^{\delta_1}, \delta_1 + \delta_2)\)。
考慮 \(g = h_n\),一個區間 \([i, j]\) 的信息等於 \(g\) 當且僅當 \(h_{j - 1} + g \beta^{\delta_{j - 1}} = h_i\)。
那么我們從后往前枚舉 \(j\),維護一個 \(h_i\) 的桶,以統計答案。
把 \(h\) 哈希一下就可以存進桶里了,為了防止沖突需要使用雙哈希。
時間復雜度為 \(\mathcal O (N \cdot \mathcal T (\mathrm{hash}))\),評測鏈接。
agc031_d
根據題意,我們可以得到 \(a_i = a_{i - 1} {(a_{i - 2})}^{-1}\)。其中 \(q p\) 表示置換的復合,滿足 \({(q p)}_i = q_{p_i}\)。
將 \(a_0\) 至 \(a_{11}\) 列出,可得:
所以是有個長度為 \(6\) 的循環節。
令 \(z = q p^{-1} q^{-1} p\),則 \(a_K\) 可以表示為 \(z^{K \div 6} a_{K \bmod 6} {(z^{-1})}^{K \div 6}\)。
時間復雜度為 \(\mathcal O (N \log K)\),評測鏈接。
cf587D
容易發現這是一個 2-SAT 的形式。
要求刪除 \(t\) 盡量小的邊,那就先二分答案。
不過還是要考慮建圖的問題。
如果直接建圖的話,會發現每個點周圍的邊都會互相影響,也就是刪掉其中一條就不能刪另一條。
直接建邊的話要建 \(\mathcal O ({deg}^2)\) 條。
其實限制就是,一個點周圍的邊,最多刪一條。
那么我們再在 2-SAT 模型中新建若干個變量,\(s_i\) 表示前 \(i\) 條邊是否被刪去。
如果 \(s_i = 1\),那么就有 \(s_{i + 1} = 1\),\(a_{i + 1} = 0\)。
如果 \(a_i = 1\),那么就有 \(s_i = 1\)。
大概是個鏈前綴和的形式。
這樣子邊數就是線性的了。
時間復雜度為 \(\mathcal O (m \log m + m \log t)\),評測鏈接。
cf674F
這里我就抄 CMXRYNP 的題解了。
從能夠得到的信息考慮。
最多有 \(\min\{p, n - 1\}\) 只熊要去睡覺,我們先讓 \(p\) 對 \(n - 1\) 取 \(\min\)。
那么對於每只熊,我們可以知道它有沒有去睡覺,如果有可以知道它在第幾晚去睡覺的。
所以最多的情況數就是:
也就是枚舉 \(k\) 只熊去睡覺了,然后 \(i\) 是天數。
這是桶數量的一個上界。因為再怎么改變策略最后也只有這么多種情況。
我們可以證明這個上界是可以被達到的。
把所有情況編號,對於第 \(x\) 種情況,令沒有去睡覺的熊不碰第 \(x\) 個桶,在第 \(a\) 天去睡覺的熊恰好在第 \(a\) 晚去喝第 \(x\) 個桶里的飲料。
這樣子如果第 \(x\) 桶里是酒,就恰好會生成這種情況,所以每種答案對每種情況是一個滿射,然而它們數量相同,所以是一一對應的。
所以只要求出這個多項式的系數就行,系數就是組合數模 \(2^{32}\),記一下 \(2\) 的次數,遞推一下就行。
時間復雜度為 \(\mathcal O (p \log \mathrm{MOD} + q \cdot p)\),其中 \(\log \mathrm{MOD}\) 為快速冪復雜度,評測鏈接。
agc024_e
相當於是,從一個空串開始,每次往里面加入一個 \([1, K]\) 之間的字符,加入 \(N\) 次,使得字符串的字典序遞增。
先把每個串的末尾加上字符 \(0\)。
可以發現,加入字符(假設我們在字符 \(y\) 前插入字符 \(x\))后字典序遞增,當且僅當:
- \(x > y\)。
- \(x = y\),且 \(x > y\) 之后第一個不同的字符。
我們插入的時候,只關心字符串是否相同,不關心插入的位置。
所以假設是第二種情況,我們可以把插入的位置往后挪到那個不同的字符之前。
這樣子既不會統計到重復的串,又避免了難考慮的 2 情況,一舉兩得。
現在只需要考慮 1 情況,也就是每次插入的字符必須插入在一個比它小的字符之前。
我們可以把插入的形式抽象化為一棵樹:
根節點為 \(0\),權值也為 \(0\)。
假設第 \(i\) 次在字符 \(y\) 之前插入了字符 \(x\),如果 \(y\) 是在第 \(j\) 次插入的,就令 \(i\) 為 \(j\) 的兒子,權值為 \(x\)。
可以發現這樣的樹,只需要滿足:節點編號為 \(0 \sim N\),節點權值為 \(0 \sim K\),且孩子節點的編號和權值,要分別大於當前節點的編號和權值。
考慮令 \(dp(i, j)\) 表示,一棵 \(i\) 個點的樹,節點編號為 \(0 \sim i - 1\),根節點權值為 \(j\),且滿足上述條件的方案數。
有轉移:\(\displaystyle dp(i, j) = \sum_{k = 1}^{i - 1} \binom{i - 2}{k - 1} dp(i - k, j) \sum_{j < x \le K} dp(k, x)\)。
組合意義是:考慮編號為 \(1\) 的節點,它一定是根節點的孩子,且形成一個子問題,枚舉 \(1\) 節點的子樹大小,假設為 \(k\),將除了 \(0, 1\) 之外的 \(i - 2\) 個編號分配給除了 \(1\) 之外的 \(k - 1\) 個 \(1\) 的子樹中的點,這里貢獻一個 \(\displaystyle \binom{i - 2}{k - 1}\);除了 \(1\) 子樹外的大小為 \(i - k\),這里貢獻一個 \(dp(i - k, j)\);\(1\) 節點的權值為 \((j, K]\) 中的整數,這里貢獻一個 \(\displaystyle \sum_{j < x \le K} dp(k, x)\)。
后一個和式用后綴和優化,狀態轉移的總時間復雜度為 \(\mathcal O (N^2 K)\)。
答案就為 \(dp(N + 1, 0)\)。
時間復雜度為 \(\mathcal O (N^2 K)\),評測鏈接。
2020-02-10
cf538G
通過坐標變化,把曼哈頓距離轉成切比雪夫距離。
也就是說四個方向 RLUD
,原本是橫縱坐標選取其中一個加減 \(1\),現在變成可以分別確定橫縱坐標是加還是減。
所以這就變成了一個一維的問題,好考慮一些。具體地說,只要把 \((x, y)\) 變成 \((x + y, x - y)\) 就行。
接下來考慮一維問題,只要分別解決了兩個一維問題,顯然就可以拼成答案。
假設操作序列為 \(c\),則 \(c\) 是個 \(\pm 1\) 串。通過 \(x_i \gets (x_i + t_i) / 2\),可以把 \(c\) 轉成 \(01\) 串。
則我們考慮 \(c\) 是 \(01\) 串的情況,令 \(s\) 為 \(c\) 的前綴和。
則有 \(s_i \le s_{i + 1} \le s_i + 1\)。
考慮每個時刻,還有 \(x_i = \lfloor t_i / l \rfloor s_l + s_{t_i \bmod l}\)。
令 \(s = s_l\),如果確定了 \(s\),就可以直接判斷是否合法了。
具體的說,根據獲得的 \(n\) 個時刻的信息,可以確定出 \(s_i\) 中一些位置的值了,然后根據 \(s_i \le s_{i + 1} \le s_i + 1\) 進一步判斷。
但是現在不知道 \(s\),如何求出 \(s\) 呢。
我們把所有信息:\(c_i s + s_{p_i} = x_i\) 按照 \(p_i\) 從小到大排序。
(\(c_i = \lfloor t_i / l \rfloor\),\(p_i = t_i \bmod l\))
不過在排序之前,要在這些信息里加上兩條:\(0 s + s_0 = 0\) 和 \((-1) s + s_l = 0\)。
然后考慮相鄰的兩條信息,就可以列出不等式確定 \(s\) 的范圍。
最后求得的 \(s\) 是一個區間,任取里面任何一個值都可以。
具體證明我也不太懂,反正 AC 了(
其它實現細節見代碼。
時間復雜度為 \(\mathcal O (n \log n + l)\),評測鏈接。
agc035_d
可以發現 \(A_1\) 和 \(A_N\) 沒啥用,不用考慮它們,然后最后加到答案里去就行。
那也就是說,現在有 \(N - 2\) 個數排成一行,你每次可以刪掉其中一個,它就會加到左右兩邊去。
特別的,如果它在最左邊,它就會被加到一個變量 \(L\) 上,如果它在最右邊,它就會被加到一個變量 \(R\) 上。
最后要讓 \(L + R\) 最小。
這時可以考慮倒着做。假設最后一個刪掉的元素,是 \(i\)。
那么 \(i\) 左邊的數,一部分扔到 \(L\) 里了,一部分扔到 \(i\) 上了,\(i\) 右邊的數,一部分扔到 \(R\) 里了,一部分扔到 \(i\) 上了。
然后刪除 \(i\) 本身,就有那些扔到 \(i\) 上的數,以及 \(i\) 本身,都會被加到 \(L\) 和 \(R\) 上。
那么我們假設,\(i\) 左邊的數刪除后,加到 \(i\) 上,總共加了 \(x\)。那么這 \(x\) 最后產生的貢獻就是 \(2x\),因為加到了 \(L\) 和 \(R\) 上。
右邊同理,只不過換了個方向,也是兩倍貢獻。
既然倒着考慮了,那就要想到區間 DP。我們觀察 \(i\) 左邊的區間,這段區間中的數,加到左邊會對總答案貢獻 \(1\) 倍,但是加到右邊會貢獻 \(2\) 倍。
於是定義如下狀態:\(dp(l, r, cl, cr)\) 表示考慮區間 \([l, r]\) 中的數,把它們刪除后,會對總答案貢獻 \(cl \cdot L + cr \cdot R\),要使這個貢獻最小。
則最終答案為 \(dp(2, N - 1, 1, 1) + A_1 + A_N\)。
有轉移:
特別地,如果 \(l > r\),則 DP 值為 \(0\)。
容易發現,DP 狀態數的上界是 \(\mathcal O (N^2 2^N)\),因為區間只有 \(\mathcal O (N^2)\) 對,而后面的系數的增長可以看作一個 \(N\) 層的二叉樹的形態。
經過一些精細計算,其實 DP 狀態數和轉移數只有 \(\mathcal O (2^N)\),這里就略去不證了。
時間復雜度為 \(\mathcal O (2^N)\),評測鏈接。
agc033_e
不失一般性,我們假設 \(S[1] = \texttt{R}\),如果不成立則把兩種顏色互換即可,不影響答案。
因為一開始就必須走紅弧,所以環上不能出現相鄰的藍弧。也就是說,環上的每一段藍弧的長度均為 \(1\)。
如果 \(S\) 全部都是 \(\texttt{R}\),則不需要其他限制了,答案就為 \(2F_{N - 1} + F_N\)(\(F\) 為斐波那契數列,\(F_0 = 0, F_1 = 1\))。
否則至少有一個 \(\texttt{B}\),初始的一段 \(\texttt{R}\) 后必然會跟着一個 \(\texttt{B}\),所以那時必須要走到藍弧旁邊。
由此可得,一定不會出現一段連續的紅弧,滿足長度為偶數。也就是說每段連續的紅弧的長度一定是奇數。
如果出現了長度為偶數的紅弧,則如果一開始的位置在這段弧上,且到兩端的藍弧的距離的奇偶性和 \(S\) 中第一段 \(\texttt{R}\) 的長度不一樣,就一定不可能在 \(\texttt{R}\) 結束時到達藍弧旁邊(注意到因為長度是偶數,才有到兩端的藍弧的距離的奇偶性相同。如果長度為奇數,能保證恰好有一端距離的奇偶性與 \(S\) 中第一段 \(\texttt{R}\) 的長度相同)。
進一步地,假設 \(S\) 中第一段 \(\texttt{R}\) 的長度為 \(l_1\),則每段紅弧的長度,不能超過 \((l_1 + [l_1 \bmod 2 = 0])\)(因為恰好有一端是可行的,到那一端的距離不能太大)。
接着,考慮 \(S\) 之后的每一段連續的 \(\texttt{R}\)。
如果這一段 \(\texttt{R}\) 之后沒有接着一個 \(\texttt{B}\),也就是說它在 \(S\) 的末尾,那么對它就沒有限制。
否則,考慮它的長度,假設為 \(l_i\)。因為這一段 \(\texttt{R}\) 的上一個字符必然也是 \(\texttt{B}\)(不是第一段了),所以一開始時必然是在某一段紅弧的端點上。如果 \(l_i\) 為奇數的話,就要走到對面的端點上才行,否則一直在相鄰的紅弧上反復橫跳就行。也就是說,如果 \(l_i\) 為奇數的話,這一段紅弧的長度最長不能超過 \(l_i\);如果是偶數的話不產生影響。當然,因為起點是任選的,所以每一段紅弧也都具有了這個性質。
總的來說,就是說每一段紅弧的長度被限制了,最小是 \(1\),最大不妨令它為 \(k\),且要是奇數。然后要計算形成一個環的方案數。
我們把一段紅弧,和它在逆時針方向的第一個藍弧,算作一段,這樣每一段的長度就必須是 \(2 \sim (k + 1)\) 之間的偶數,所以 \(N\) 也必須是偶數。
環上的情況不好考慮,必須要轉化成序列。
我們考慮第一個弧所在的那一段,假設那一段的長度為 \(x\),則有 \(x\) 種方法旋轉,使得第一個弧仍然在那一段中。
那么也就是說,對於所有的權值是 \(\le k\) 的正偶數,總和為 \(N\) 的序列 \(A\),每一個序列會為答案貢獻 \(A_1\) 種方案。
也就是枚舉 \(A_1\),然后計算總和為 \(N - A_1\) 的序列的數量,乘以 \(A_1\) 后貢獻給答案。
總和為 \(i\) 的序列的個數很好算,只要枚舉最后一個元素是多少就行了,有轉移:\(\displaystyle f(i) = \sum_{j = 2}^{k} [j \bmod 2 = 0] f(i - j)\)。
用前綴和優化一下就完事了。
時間復雜度為 \(\mathcal O (N + M)\),評測鏈接。
2020-02-11
cf634F
如果固定上下邊界,那么中間的點,按照縱坐標排序,就可以統計答案了。所以這樣子是 \(\mathcal O (r^2 n)\) 的。
那我們固定上邊界,往下推下邊界呢?那就是變成每次插入一個點,會影響它周圍的 \(k\) 個點對答案的貢獻。
但是動態插入,比較不好維護。那我們就從下往上推下邊界,現在就變成刪除,可以用鏈表快速定位和找周圍的 \(k\) 個點。
時間復雜度為 \(\mathcal O (n \log n + r^2 + r n k)\),評測鏈接。
2020-02-12
cf666E
因為不會 SAM,所以用 SA。
我們考慮 Height 數組的 Kruskal 重構樹,其實是和后綴樹等價的。
那一次詢問就是查詢一棵子樹中,出現次數最多的顏色,以及它出現的次數。
線段樹合並即可(好像是我第一次寫線段樹合並)。
時間復雜度為 \(\mathcal O ((l + q) \log m)\),其中 \(\displaystyle l = |s| + \sum |t_i|\),評測鏈接。
cf611H
可以發現只要是無序對 \((a_i, b_i)\) 相同的邊,都可以只看做一類,這樣就只有最多 \(6 (6 + 1) / 2 = 21\) 類邊。
同時位數相同的點,也可以看作一類,這樣只有最多 \(6\) 類點。
令 \(m = \lfloor \log_{10} n \rfloor + 1\),點的類數就為 \(m\),邊的類數就為 \(m (m + 1) / 2\)。
可以發現不同種類的點,不管怎么樣也還是要連接起來的。
那么先特判一下 \(m = 1\) 的情況,然后可以證明一個結論:存在一種方案,滿足:
- 每一類點都選出一個“關鍵點”,例如第 \(i\) 類點的關鍵點編號可以為 \({10}^{i - 1}\)。
- 只考慮這 \(m\) 個關鍵點,它們形成的導出子圖,是一棵樹,也就是一個 \(m\) 個點 \(m - 1\) 條邊的樹連接了所有“關鍵點”。
- 其它所有點只與“關鍵點”連接,也就是不存在“非關鍵點”之間的連邊。
詳細證明這里從略。
那么,我們考慮枚舉連接所有“關鍵點”的樹形態,比如使用 Prüfer 序列枚舉,這部分的時間復雜度為 \(\mathcal O(m^{m - 2})\)。
枚舉完成后,對應種類的邊就用掉了對應條,這里記得先扣掉。
然后考慮每一條邊 \((u, v)\),可以是 \(u\) 類“非關鍵點”連到 \(v\) 類“關鍵點”上,也可以是 \(v\) 類“非關鍵點”連到 \(u\) 類“關鍵點”上。
總之,一條邊 \((u, v)\) 將會把 \(u\) 類或者 \(v\) 類的“非關鍵點”的剩余個數減去 \(1\)。
這樣一來就可以轉化為一個帶權(重數)二分圖完美匹配的模型。
具體地說,左側有 \(m (m + 1) / 2\) 個點,表示每一類邊,右側有 \(m\) 個點,表示每一類點。
左側的每個點,帶的權值(重數)為剩余的對應類型的邊的數量。
右側的每個點,帶的權值(重數)為剩余的對應類型的點的數量。
不難發現這兩個數量之和相等。左側的每個點,假設它對應的邊的類型為 \((u, v)\),它向右側的 \(u, v\) 類點對應的點分別連邊。
使用網絡流可以解決帶重數的二分圖匹配問題,這里寫個 Dinic 水過去。
Dinic 跑完之后也可以直接構造方案了。
時間復雜度為 \(\mathcal O (m^{m + 4})\),評測鏈接。
2020-02-13
cf613E
對於 \(|w| \le 2\) 的情況,我們進行特判,這是為了之后寫起來分類討論可以簡潔一些。
觀察一下最終的行走方式可能會變成啥樣:
很多情況下,會變成這個樣子。
注意到可以分成三段,左邊一個 U 形,中間一個只會向右走的形狀,右邊又一個 U 形。
啊,為啥說中間是只會向右走?因為我們是這么欽點的,當然也可能是從右邊出發往左走,這時只要把 \(w\) 反轉,再求一次就行。
我們可以處理出,從一個地方分段,會不會產生向左的,長度為某個值的 U 形。
這可以通過預處理 LCP 做到。
同理可以處理出,從一個地方分段,會不會產生向右的,長度為某個值的 U 形。
處理上述兩個數組,它們就能夠作為第一部分和第三部分。
我們把第二部分接在第一部分后,記 \(f(i, j, k)\) 表示,當前第二部分走到了 \((i, j)\),並且匹配了 \(w\) 的前 \(k\) 個字符,並且不是從同一列走來的方案數。
類似地,記 \(g(i, j, k)\) 為必須從同一列走來的方案數。則 \(f, g\) 之間可以互相轉移,這部分可以 \(\mathcal O (n |w|)\) 處理。
然后考慮在 DP 到 \((i, j, k)\) 時,接上第三部分即可,可以直接判斷接不接得上。
當然還有一些其他情況沒有討論的,比如三個部分中的某一部分並不存在,甚至是兩個部分不存在之類的,仔細討論一下即可。
注意要不重不漏,特別注意 \(w\) 反轉后不要統計重復了。
時間復雜度為 \(\mathcal O (n |w|)\),評測鏈接。
cf566E
如果兩個集合的交為 \(2\),則交出來的這兩個點,之間一定有連邊。
這樣可以確定樹中所有非葉子節點之間的連邊情況。
先特判非葉子節點數為 \(0, 1, 2\) 的情況。
為 \(0\) 的話就是 \(n = 2\);為 \(1\) 的話就是菊花,每個集合大小都是 \(n\);為 \(2\) 的話就是有恰好兩個集合大小是 \(n\)。
現在非葉子節點數至少是 \(3\)。那么我們需要確定每個葉子掛在了哪個非葉子上。
注意到我們在給非葉子節點連邊的時候,就可以處理出每個非葉子節點,與其相連的非葉子節點的集合,也就是距離 \(\le 1\) 的集合。
那么我們依次考慮每個葉子,它對應的集合就是所有集合中,包含這個葉子的,大小最小的那個。
在這個集合中,去掉所有葉子節點,就得到了與它相連的非葉子節點的鄰接非葉子節點集合。
再枚舉每個非葉子節點,就可以判斷具體是和哪一個非葉子節點相連的了。
時間復雜度為 \(\displaystyle \mathcal O \!\left( \frac{n^3}{w} \right)\),其中 \(w\) 為字長,評測鏈接。
cf573E
考慮一個貪心策略:一開始選空集,然后每次選一個不在集合中的數加入集合,具體選哪個數呢?選擇讓新的答案最大的數即可。
然后集合大小從 \(0\) 逐漸增大到了 \(n\),得到了 \(n + 1\) 個答案,我們選取其中最大的一個輸出。
我們發現這樣做成功 TLE 了(悲),但是並沒有 WA,說明貪心是對的(確信)。
具體證明請下載 徐翊軒的題解 查看。
那么我們只需要快速維護這個貪心,具體地說,每個位置有一個權值 \(b_i\) 和一個固定的值 \(a_i\),需要支持四種操作:
- 前綴 \(b_i\) 加相同值。
- 后綴 \(b_i\) 加 \(a_i\)。
- 查詢 \(b_i\) 的全局最大值。
- 刪除一個位置。
一般線段樹沒法做,我們考慮分塊。(其實這是一種經典分塊類型)
每 \(\sqrt{n}\) 個元素分一塊,那對於每一塊就要實現:
- 整體加。
- 整體加 \(a_i\)。
- 查詢整體最大值。
- 重構。
可以發現大概是類似斜率優化那套式子,維護上凸殼即可。
注意到 \(a_i\) 始終不變,而要求的斜率不斷遞減,可以用單調隊列維護,重構的時候也不用重新排序了。
本題還有 \(\mathcal O (n \log n)\) 的做法,在題解中同樣可以看到。不過因為要手寫平衡樹,我比較懶就不寫了。
時間復雜度為 \(\mathcal O (n \sqrt{n})\),評測鏈接。
2020-02-18
cf627F
設初始時 \(0\) 在 \(s\),目標時在 \(t\)。
注意到操作的本質是 \(0\) 的移動,同時操作具有可逆性。
因此,我們先不考慮次數最少的要求,先讓 \(0\) 從 \(s\) 以最短距離移動到 \(t\)。
如果此時已經滿足目標狀態了,說明不需要加入新的邊,此時 \(0\) 經過的距離即為最少步數。
否則,接下來我們只能加入一條新的邊,然后讓 \(0\) 從 \(t\) 出發,走到包含這條新邊的環上距離 \(t\) 最近的點 \(p\),繞若干次完整的圈之后,回到 \(t\)。
觀察這樣操作對權值的變化可以得出,\(t\) 到 \(p\) 的路徑上的所有點的權值都不會改變,同時每繞圈一次,環上除了 \(p\) 之外的點上的權值變化形成一個循環,而繞若干圈則為一個輪換。
因此,權值要改變的點加上 \(p\) 應該在樹上形成一條路徑。
由此我們能夠確定連邊 \((u,v)\),可以 \(t\) 為根,找到所有權值需要改變的點,\(p\) 即為這些點中深度最小的點的父節點,而路徑 \((u,v)\) 則由 \(p\) 和這些點構成。
如果深度最小的點的父節點不唯一,或者 \(p\) 和這些點無法構成一條路徑,或者這些點的權值不是目標權值的一個輪換,則說明無解。
最后來考慮最小化操作次數。
對於一條加邊 \((u,v)\),繞圈的方向有兩種 \(u \to v\) 和 \(v \to u\),分別計算取 \(\min\) 即可。
假設從 \(u \to v\),由這個輪換對循環的次數 \(c\) 可以得到最小次數為 \(2\cdot \operatorname{dist}(t, p) + c \cdot (\operatorname{dist}(u, v) + 1)\)。
但注意這個最小次數是在先將 \(0\) 從 \(s\) 移到 \(t\) 的前提下,因此如果有重復的路徑需要減掉。
准確地說,如果是 \(u \to v\),那就是將 \(0\) 直接從 \(s\) 經過樹邊移動到 \(u\),然后經過新加的邊移動到 \(v\),然后在這個環上再繞 \((c - 1)\) 圈回到 \(v\),最后經過樹邊移動到 \(t\)。此時的答案也就是 \(\operatorname{dist}(s, u) + (c - 1) \cdot (\operatorname{dist}(u, v) + 1) + \operatorname{dist}(v, t) + 1\)。
如果是 \(v \to u\),只要把 \(u, v\) 互換,並重新計算循環的次數 \(c\) 即可。
時間復雜度為 \(\mathcal O (n)\),評測鏈接。
2020-02-19
arc093_f
淘汰賽的比賽結構是一個完全二叉樹,假設玩家 \(1\) 被安排在了某個位置,則他要最終獲得勝利的話,需要打敗 \(N\) 個對手。
這 \(N\) 個對手分別來自大小為 \(2^0, 2^1, 2^2, \ldots , 2^{N - 1}\) 的子樹中。
也就是說,它們是那些對應的子樹中的最小值。
要讓 \(1\) 取得勝利,這些值中不能有那 \(M\) 個 \(A_i\) 之一。
這相當於,把除了 \(1\) 以外的 \(2^N - 1\) 個數染上 \(N\) 種顏色,第 \(i\) 種顏色恰好要染 \(2^{i - 1}\) 個數。
而且對於每種顏色,最小的,染上這種顏色的數,不能是任何一個 \(A_i\)。
然后我們考慮容斥原理,假設一個集合中的 \(A_i\) 都必須是某個顏色的最小值。
可以發現讓 \(A_i\) 從大到小 DP 會比較合適。記一個狀態表示比當前值大的 \(A_i\) 被強制選取了哪些顏色的最小值,也就是說哪些顏色已經被用掉了。
轉移的時候,該 \(A_i\) 可以不強制選,直接轉移;或者強制選成某個還未被選擇的顏色 \(k\) 的最小值,DP 值乘上 \(\displaystyle \binom{s - 1}{2^{k - 1} - 1}\),其中 \(s\) 表示后面還沒有被選中的數的個數,\(s\) 可以直接由當前 \(A_i\) 和選取的顏色狀態計算得出。
最后答案就是容斥得到的染色方案數,乘以 \(\displaystyle 2^N \prod_{i = 1}^N (2^{i - 1})!\),這是因為每個子樹內可以任意排,然后 \(1\) 每次可以從左子樹或右子樹上來。
時間復雜度為 \(\mathcal O (M N 2^N)\),評測鏈接。
2020-02-20
cf506E
不考慮題目中的“在原串中插入”,我們直接統計最終的長度為 \(N = |s| + n\) 的回文串的個數。
接下來的問題是:給定一個回文串,如何判斷 \(s\) 是否作為一個子序列出現。
當然可以直接子序列自動機,但是這樣子的性質不夠好。考慮從 \(s\) 的兩側進行匹配。
假設當前回文串為 \(t\),我們使用 \(t\) 兩側的字符對 \(s\) 兩側的字符進行匹配:
假設 \(t\) 兩端的字符為 \(c\),如果 \(s\) 左端的字符也為 \(c\),就刪去這個字符,右邊同理。
以 \(s = \mathtt{abaac}, t = \mathtt{{\color{red}b}{\color{magenta}a}{\color{blue}c}{\color{Tan}b}{\color{ForestGreen}a}{\color{Tan}b}{\color{blue}c}{\color{magenta}a}{\color{red}b}}\) 為例:
- 用 \(\mathtt{{\color{red}b}}\) 去匹配 \(s\) 的兩端,\(s\) 變為 \(\mathtt{abaac}\)。
- 用 \(\mathtt{{\color{magenta}a}}\) 去匹配 \(s\) 的兩端,\(s\) 變為 \(\mathtt{{\color{magenta}a}baac}\)。
- 用 \(\mathtt{{\color{blue}c}}\) 去匹配 \(s\) 的兩端,\(s\) 變為 \(\mathtt{{\color{magenta}a}baa{\color{blue}c}}\)。
- 用 \(\mathtt{{\color{Tan}b}}\) 去匹配 \(s\) 的兩端,\(s\) 變為 \(\mathtt{{\color{magenta}a}{\color{Tan}b}aa{\color{blue}c}}\)。
- 用 \(\mathtt{{\color{ForestGreen}a}}\) 去匹配 \(s\) 的兩端,\(s\) 變為 \(\mathtt{{\color{magenta}a}{\color{Tan}b}{\color{ForestGreen}a}a{\color{blue}c}}\)。
注意,這里只能匹配其中一個字符,因為 \(\boldsymbol{t}\) 中只剩下一個 \(\mathtt{{\color{ForestGreen}a}}\) 了!
如果 \(s\) 少一個 \(\mathtt{a}\) 或者 \(t\) 多一個 \(\mathtt{{\color{ForestGreen}a}}\),就能全部匹配。
如果按照這種方式全部匹配完了,就是合法的串。
由此我們可以構造一個 DP:\(dp(x, i, j)\) 表示確定了 \(t\) 的左右兩端各 \(x\) 個字符后,恰好匹配到 \(s\) 中的子串 \(s[i : j]\) 的 \(t\) 的方案數。
並且一個特殊的狀態 \(dp(x, \mathrm{done})\) 表示匹配完了。
則答案就為 \(\displaystyle dp \!\left( \left\lceil \frac{N}{2} \right\rceil\!, \mathrm{done} \right)\)。
對應的轉移圖如下:
但是因為 \(N\) 太大,沒法直接這樣做,直接做的復雜度是 \(\mathcal O ({|s|}^2 N)\) 的。
觀察到這個轉移圖,顯然就是用來矩陣快速冪的,但是還是不行,復雜度是 \(\mathcal O ({|s|}^6 \log N)\) 的。
所以還是觀察一下性質,比如我們可以發現,紅色點就代表 \(s\) 的兩端不同的情況,綠色點表示相同的情況。
那么要到達終點,如果經過了 \(n_1\) 個紅色點,就必須要經過 \(\displaystyle \left\lceil \frac{|s| - n_1}{2} \right\rceil\) 個綠色點。
然后發現終點前的點一定是綠色點,所以最多經過 \(|s| - 1\) 個紅色點,也就是說經過的紅色點的數量在 \(0\) 到 \(|s| - 1\) 內。
我們單獨把一條從起點到終點的鏈拿出來,可以發現,經過的紅點和綠點的順序實際上沒有影響,也就是說把紅點提前答案不變:
這個性質十分重要,因為本質不同的鏈的個數只有 \(\mathcal O (|s|)\) 個,所以只要求出每種鏈的個數就行了,同樣可以使用類似的 DP 得到。
這樣的話,考慮在每一條鏈上做矩陣快速冪,得到的答案乘以鏈的條數再相加就是總答案,復雜度是 \(\mathcal O ({|s|}^4 \log N)\) 的。
我們可以更進一步優化,考慮這樣的自動機(字符串長度為 \(|s| = 5\) 時,也就是和剛才舉的例子相同):
其中 \(g_0 \sim g_{|s| - 1}\) 分別表示經過的紅點個數分別為對應值的鏈的個數。
可以發現恰好滿足每一條本質不同的鏈都能夠被表示出,而且不重復不遺漏。
在這個自動機上做矩陣快速冪就行了,因為加了一個空的起點,所以要多走一步。
但是這樣直接求的話,對於 \(N\) 是奇數的情況會多算,就是前文提到的那種情況(最中心的字符只能匹配一個)。
我們這樣考慮,先求出在 \(\displaystyle \left\lfloor \frac{N}{2} \right\rfloor\) 步內就能到達終點的方案數,乘以 \(26\)(還能再走一步)。
然后再加上在 \(\displaystyle \left\lfloor \frac{N}{2} \right\rfloor\) 步時恰好到達一開始的自動機中的 \(s\) 被刪到長度為 \(1\) 時的節點的方案數。
計算第二種情況時,也要重新計算一下 \(g_0 \sim g_{|s| - 1}\),最終就能求得總答案了。
時間復雜度為 \(\mathcal O ({|s|}^3 \log N)\),評測鏈接。
arc096_e
考慮容斥,枚舉有 \(a\) 個只出現了一次,\(b\) 個一次都沒出現。
則給答案貢獻 \(\displaystyle {(-1)}^{a + b} \binom{n}{a} \binom{n - a}{b} 2^{2^{n - a - b}} \sum_{x = 0}^{a} {a \brace x} {(2^{n - a - b})}^x\)。
如果令 \(c = a + b\),變換為 \(\displaystyle {(-1)}^c \binom{n}{c} 2^{2^{n - c}} \sum_{x = 0}^{c} {(2^{n - c})}^x \sum_{a = x}^{c} {a \brace x} \binom{c}{a}\)。
考慮這個恆等式:\(\displaystyle \sum_{i = x}^{n} {i \brace x} \binom{n}{i} = {n + 1 \brace x + 1}\)。
所以答案為 \(\displaystyle \sum_{c = 0}^{n} {(-1)}^c \binom{n}{c} 2^{2^{n - c}} \sum_{x = 0}^{c} {(2^{n - c})}^x {c + 1 \brace x + 1}\)。
時間復雜度為 \(\mathcal O (N^2 + N \log M)\),評測鏈接。
2020-02-21
cf575E
可以證明如下結論:
在平面直角坐標系中,給定若干個不全都共線的點。
要作一個半徑盡量大的圓,使得該圓包含所有給定點,並經過至少三個給定點。
構造給定點構成的凸包,並要求凸包上不存在共線的三個頂點。由於這些點不全都共線,所以一定存在這樣的凸包。
則有結論:要求的圓一定經過凸包上三個相鄰頂點。
具體證明請下載 任清宇的題解 查看。
所以只要求出給出的點集的凸包后,枚舉凸包上相鄰三點計算並更新答案即可。
具體地說,由於每個人能夠到達的點的凸包是一個點,或一個 \(3 \sim 6\) 邊形,只要求出每個人對應的凸包的頂點,這可以通過簡單的討論求出,再合並求一次大凸包即可。
時間復雜度為 \(\mathcal O (n \log n)\),評測鏈接。
cf607E
為了方便考慮,把坐標系平移到以 \((p, q)\) 為原點處。
那么以原點為圓心作圓,只要找到圓內有 \(m' < m\) 個交點的最大半徑即可。
那么答案就等於圓內交點到原點的距離之和,加上 \(m - m'\) 倍的半徑。
二分答案后考慮如何 check 是否有 \(< m\) 個交點。
把每個與圓有交的直線拿出來,就變成圓上的一條弦,對應了圓上極角序的一個區間。
就變成了對相交但不包含的區間對計數的問題,是二維偏序問題。
這部分時間復雜度為 \(\mathcal O (n \log n (\log v - \log \varepsilon))\)。
確定了對應半徑后,再使用類似方法在 \(\mathcal O (n \log n + m)\) 的時間內統計交點到原點的距離即可。
時間復雜度為 \(\mathcal O (n \log n (\log v - \log \varepsilon) + m)\),評測鏈接。
2020-02-22
arc092_f
對於一條邊 \(u \to v\),將它反向后變成 \(v \to u\),會對原圖的強連通分量個數造成影響,當且僅當:
- 忽略這條邊后,\(u\) 能直接或間接到達 \(v\)。
- 忽略這條邊后,\(v\) 能直接或間接到達 \(u\)。
這兩個條件僅恰好滿足一個。證明不難,請自行腦補。
其中,忽略 \(u \to v\) 后,詢問 \(v\) 是否能夠到達 \(u\),和不忽略其實也沒啥區別,所以這部分可以直接做,\(\mathcal O (NM)\) 的復雜度就可以接受了,當然你也可以用 bitset 做 \(\mathcal O (M + NM / w)\)。
然后考慮忽略 \(u \to v\) 后,詢問 \(u\) 是否能夠到達 \(v\),也就是只要存在第一條邊不走 \(u \to v\) 的簡單路徑就行。
我們考慮對於所有的起點相同,也就是 \(u\) 相同的 \(u \to v\) 計算這個東西,那么只要一次的時間復雜度為 \(\mathcal O (M)\) 就可以接受了。
首先把 \(u\) 的出邊排成一排,假設終點分別為 \(v_1, v_2, \ldots , v_k\)。
那么先按照正序,也就是 \(v_1, v_2, \ldots , v_k\) 的順序進行 DFS,並記錄每個點是從哪個點到達的(就是從哪個 \(v_i\) 出發),記做 \(p(v_i)\)。
然后按照逆序,也就是 \(v_k, v_{k - 1}, \ldots , v_1\) 的順序進行 DFS,並記錄每個點是從哪個點到達的,記做 \(q(v_i)\)。
如果一個 \(v_i\) 可以從其它 \(v_j\)(\(j \ne i\))出發到達它,當且僅當 \(p(v_i) \ne q(v_i)\),只要判斷這個條件即可。
時間復雜度為 \(\mathcal O (NM)\),評測鏈接。
2020-02-23
agc023_f
第一步,必須把根節點刪掉。
然后可以發現,如果刪掉一個節點之后,它的孩子中有 \(0\),那就可以立刻把孩子也刪掉,這樣答案不會變得更劣。
那我們把 \(0\) 和它的父親並成一個連通塊,表示這個連通塊可以一次性取完,最后整棵樹就變成了一些不相交連通塊。
然后會發現,如果此時我們把每個連通塊看成一個節點,還是一棵樹的結構,但是這時每個連通塊內就有若干個 \(0\) 和 \(1\) 混合了。
現在僅考慮新樹的兩個節點 \(u, v\),忽略其它的影響:
假設 \(x\) 中 \(0, 1\) 的個數分別為 \(x_0, x_1\),則如果 \(u\) 排在 \(v\) 前面,就會增加 \(u_1 v_0\) 對逆序對,反之增加 \(v_1 u_0\) 對。
如果 \(u_1 v_0 < v_1 u_0\),則 \(u\) 排在 \(v\) 前面肯定更優。
變換一下式子,變成 \(\displaystyle \frac{u_1}{u_0} < \frac{v_1}{v_0}\),也就是連通塊中 \(1\) 與 \(0\) 個數的比值。
考慮當前這個比值最小的連通塊,假設為 \(a\),則可以發現當 \(a\) 的父親被取到的時候,下一步一定會把 \(a\) 取了。
這是因為無論連通塊怎么合並,這個比值都不會變得比原來更小,也就不會小於 \(a\) 的比值。
所以,拿一個支持插入刪除,取出最小值的數據結構(比如 set),就可以維護了。
具體地說就是每次取出這個比值最小的連通塊,把它的它的父親合並。
時間復雜度為 \(\mathcal O (n \log n)\),評測鏈接。
2020-02-25
agc038_f
把 \(P\) 分解成不相交循環的乘積后,考慮其中一個循環 \((a_1, a_2, \ldots , a_k)\)。
不失一般性,可以把這個循環看作 \((1, 2, \ldots , k)\)。
那么對於 \(A_1\),有兩種情況:\(A_1 = 1\) 或 \(A_1 = P_1 = 2\)。
如果 \(A_1 = 1\),則考慮 \(A_k\) 有兩種情況:\(A_k = k\) 或 \(A_k = P_k = 1\),但是因為 \(A_1 = 1\),所以只能有 \(A_k = k\)。
以此類推,可以得到:對於這個循環中的所有元素 \(i\),均有 \(A_i = i\)。
如果 \(A_1 = 2\),則考慮 \(A_2\) 有兩種情況:\(A_2 = 2\) 或 \(A_2 = P_2 = 3\),但是因為 \(A_1 = 2\),所以只能有 \(A_2 = 3\)。
以此類推,可以得到:對於這個循環中的所有元素 \(i\),均有 \(A_i = P_i\)。
換句話說,對於每個循環,要么這個循環被完全保留,要么這個循環被完全拆解成一個個自環。
上述結論對 \(Q\) 和 \(B\) 當然也適用。
我們稱選擇一個循環,指這個循環被完全保留,稱不選一個循環,指這個循環被拆解成了一個個自環。
接着,考慮一個 \(P\) 中的循環 \(a\) 和一個 \(Q\) 中的循環 \(b\),假設它們共有一個元素 \(i\)。分若干類討論:
- \(P_i = Q_i = i\):無論如何,這個位置上均有 \(A_i = B_i\)。
- \(P_i = i, Q_i \ne i\):如果選擇了 \(b\),則這個位置上有 \(A_i \ne B_i\),否則不選 \(b\),則這個位置上有 \(A_i = B_i\)。
- \(P_i \ne i, Q_i = i\):如果選擇了 \(a\),則這個位置上有 \(A_i \ne B_i\),否則不選 \(a\),則這個位置上有 \(A_i = B_i\)。
- \(P_i \ne i, Q_i \ne i, P_i \ne Q_i\):如果不選 \(a\) 且不選 \(b\),則這個位置上有 \(A_i = B_i\),否則這個位置上有 \(A_i \ne B_i\)。
- \(P_i \ne i, Q_i \ne i, P_i = Q_i\):如果 \(a, b\) 同時選擇或同時不選,則這個位置上有 \(A_i = B_i\),否則這個位置上有 \(A_i \ne B_i\)。
最終需要最大化 \(A_i \ne B_i\) 的下標 \(i\) 的數量,也就是最小化 \(A_i = B_i\) 的下標 \(i\) 的數量。
如果在上述 \(5\) 種情況中,一旦發生了 \(A_i = B_i\),就賦有 \(1\) 的代價,那么就是要最小化總代價。
可以發現類似於一個文理分科模型,可以建立一個網絡流模型,求最小割得到答案。
但是因為有些條件不符合,沒法直接套用。
不過,如果把 \(Q\) 中的循環割掉與源點和匯點之間的邊的意義交換,就可以套用了。
而且可以發現,這樣建出來的圖是一個二分圖,因為 \(P\) 中的循環只和源點連邊,\(Q\) 中的循環只和匯點連邊,\(P, Q\) 之間也只會互相連邊。(如果 \(P\) 中的循環對應的節點,割掉與源點相連的邊的意義是不選它,而 \(Q\) 中的循環對應的節點的意義恰好相反的話)
所以最終是在單位容量的二分圖上求最小割,使用 Dinic 算法可以做到 \(\mathcal O (|E| \sqrt{|V|})\) 的復雜度。
時間復雜度為 \(\mathcal O (N \sqrt{N})\),評測鏈接。
agc023_d
如果 \(X_1 < S < X_N\),考慮第 \(1\) 棟樓和第 \(N\) 棟樓。
如果 \(P_1 \ge P_N\),即第 \(1\) 棟樓中的人數大於等於第 \(N\) 棟樓中的人數,則班車一定會先去第 \(1\) 棟樓。證明:
- 如果 \(N = 2\),顯然成立。
- 如果 \(N \ge 3\) 且 \(X_{N - 1} < S\),顯然除了第 \(N\) 棟樓的員工,都希望前往負方向,所以一定會前往負方向。
- 如果 \(N \ge 3\) 且 \(S < X_{N - 1}\),如果在到達第 \(1\) 棟樓之前沒有到達第 \(N - 1\) 棟樓,則結論成立,否則轉化為前兩種情況。
所以說不管怎么樣都會先前往第 \(1\) 棟樓,然后就可以一路向右徑直跑到第 \(N\) 棟樓。
這就意味着,第 \(N\) 棟樓中內的員工的回家時間,一定等於第 \(1\) 棟樓的回家時間,加上 \(X_N - X_1\)。
也就是說,第 \(N\) 棟樓中的員工,其實是和第 \(1\) 棟樓中的員工站在同一條線上的。第 \(1\) 棟樓的員工想投什么票,他們也一定會跟着投。所以說這第 \(N\) 棟樓的員工其實和第 \(1\) 棟樓的員工沒什么區別,暫時(在第 \(1\) 棟樓的員工回家之前)讓他們搬家到第 \(1\) 棟樓也對運行路徑沒有影響。
所以說,如果讓 \(P_1 \gets P_1 + P_N\),然后刪去第 \(N\) 棟樓,計算這種情況下的到達第 \(1\) 棟樓的時間,加上 \(X_N - X_1\) 就是答案。
如果 \(P_1 < P_N\),那么以上結論的方向反過來即可。
這樣遞歸下去,直到不滿足 \(X_1 < S < X_N\) 為止,那樣的話就可以直接計算答案了。
時間復雜度 \(\mathcal O (N)\),評測鏈接。
2020-02-26
agc036_d
考慮差分約束模型,圖中不存在負環等價於存在一組合法的差分約束的解。
考慮每個節點作為一個變量,第 \(i\) 個節點對應的變量為 \(x_i\)。
因為初始的邊不能刪去,所以一定有 \(x_i \ge x_{i + 1}\)。
考慮令 \(q_i = x_i - x_{i + 1}\),那么就會有 \(q_i \ge 0\)。
假設保留了一條邊權為 \(-1\) 的 \(i \to j\) 的邊,也就是說 \(i < j\) 的話:
就會有 \(x_i - 1 \ge x_j\),即 \(x_i - x_j \ge 1\),也就是說 \(q_i + q_{i + 1} + \cdots + q_{j - 1} \ge 1\)。
假設保留了一條邊權為 \(1\) 的 \(i \to j\) 的邊,也就是說 \(i > j\) 的話:
就會有 \(x_i + 1 \ge x_j\),即 \(x_j - x_i \le 1\),也就是說 \(q_j + q_{j + 1} + \cdots + q_{i - 1} \le 1\)。
反過來想,如果確定了所有的 \(q_i\),那么每一條邊就應該盡可能地保留下來,這樣代價最小。
對於邊權為 \(-1\) 的邊,是區間和 \(\ge 1\) 才能保留,也就是說如果區間和 \(= 0\) 就必須刪除。
對於邊權為 \(1\) 的邊,是區間和 \(\le 1\) 才能保留,也就是說如果區間和 \(\ge 2\) 就必須刪除。
也就是說,對於一種 \(q\) 的取值方案,\(q_i = 0\) 的每個連續段,都對應着一系列的邊權為 \(-1\) 的邊的刪除。
而區間和 \(\ge 2\) 的區間也對應着邊權為 \(1\) 的邊的刪除。
顯然可以發現,如果出現了 \(q_i \ge 2\),不如把它變成 \(1\),這樣一定會變得更優(邊 \(i \to (i + 1)\) 不用被刪除了)。
所以只需要考慮 \(q\) 的取值為 \(\{0, 1\}\) 的情況。
然后可以發現,每個 \(0\) 的連續段就對應着一部分區間的刪除,所以考慮如下 DP:
記 \(dp(i, j)\) 表示考慮到了 \(q_i\),最后一個 \(1\) 取在了 \(q_i\),倒數第二個 \(1\) 取在了 \(q_j\) 處的情況下,可以確定的代價的最小值。
\(dp(i, j)\) 可以從 \(dp(j, k)\) 轉移而來,利用二維前綴和可以快速求出轉移系數。
時間復雜度為 \(\mathcal O (N^3)\),評測鏈接。
2020-02-27
agc026_e
令 \(a_i\) 表示第 \(i\) 個 \(\mathtt{a}\) 的位置,\(b_i\) 表示第 \(i\) 個 \(\mathtt{b}\) 的位置。
考慮如何比較兩個字符串的字典序,可以發現當某個前綴相同時應該比較后綴,所以考慮從后往前 DP:
令 \(dp(i)\) 表示只考慮所有的 \(a_{i \sim N}\) 和 \(b_{i \sim N}\),也就是第 \(i\) 對以及之后的 \(\mathtt{a}, \mathtt{b}\) 的情況下的字典序最大的串。
注意不是第 \(i\) 對 \(\mathtt{a}, \mathtt{b}\) 以及它們之后的所有字符都一定選擇,而是一對一對的選擇的。
那么答案就為 \(dp(1)\)。而 \(dp(i)\) 可以從兩個方向轉移,也就是 \(a_i\) 和 \(b_i\) 保留或者刪掉。
如果刪掉,就直接從 \(dp(i + 1)\) 轉移而來。
否則考慮如果保留第 \(i\) 對 \(\mathtt{a}, \mathtt{b}\) 的話會怎么樣,根據先后順序分成兩類討論:
- \(a_i < b_i\):也就是形如 \(\cdots \mathtt{{\color{red}a}{\color{blue}a}{\color{green}b}{\color{blue}a}{\color{blue}a}{\color{green}b}{\color{red}b}} \cdots\) 的情況。
紅色的字符就是第 \(i\) 對 \(\mathtt{a}, \mathtt{b}\),綠色的字符表示第 \(i\) 對之前的字符,藍色的字符表示第 \(i\) 對之后的字符。
注意綠色的字符只可能是 \(\mathtt{b}\),而藍色的字符只可能是 \(\mathtt{a}\)。因為綠色的字符不會被保留,之后忽略它們。
既然已經確定了必須選取 \(a_i, b_i\),因為要讓字典序盡量大,所以 \(a_i\) 到 \(b_i\) 之間所有的 \(\mathtt{a}\) 都應該被刪掉。
也就是說,\(dp(i)\) 就應該等於 \(\mathtt{ab} + dp(k)\),其中 \(k\) 為完全在 \(b_i\) 之后的第一對 \(a_k, b_k\) 的編號。 - \(a_i > b_i\):也就是形如 \(\cdots \mathtt{{\color{red}b}{\color{blue}b}{\color{green}a}{\color{blue}b}{\color{blue}b}{\color{green}a}{\color{red}a}} \cdots\) 的情況。
紅色的字符就是第 \(i\) 對 \(\mathtt{a}, \mathtt{b}\),綠色的字符表示第 \(i\) 對之前的字符,藍色的字符表示第 \(i\) 對之后的字符。
注意綠色的字符只可能是 \(\mathtt{a}\),而藍色的字符只可能是 \(\mathtt{b}\)。因為綠色的字符不會被保留,之后忽略它們。
既然已經確定了必須選取 \(a_i, b_i\),因為要讓字典序盡量大,所以 \(a_i\) 到 \(b_i\) 之間所有的 \(\mathtt{b}\) 都應該被保留。
而確定要保留這些 \(\mathtt{b}\),又會導致往后包含了更多的 \(\mathtt{b}\),同理被包含的 \(\mathtt{b}\) 也應該被保留,連鎖反應會一直進行下去,直到某一次不包含了更多的 \(\mathtt{b}\) 為止。舉個例子:
考慮 \(\mathtt{{\color{blue}b}b{\color{blue}a}babbbabaaaabbabaaaabb}\),
選取 \(\mathtt{{\color{red}b}{\color{blue}b}{\color{red}a}b{\color{blue}a}bbbabaaaabbabaaaabb}\),
選取 \(\mathtt{{\color{red}{bba}}{\color{blue}b}{\color{red}a}bbb{\color{blue}a}baaaabbabaaaabb}\),
選取 \(\mathtt{{\color{red}{bbaba}}{\color{blue}{bbb}}{\color{red}a}b{\color{blue}{aaa}}abbabaaaabb}\),
選取 \(\mathtt{{\color{red}{bbababbba}}{\color{blue}b}{\color{red}{aaa}}{\color{blue}a}bbabaaaabb}\),
選取 \(\mathtt{{\color{red}{bbababbbabaaaa}}bbabaaaabb}\)。
在這種情況下,\(dp(i) = \mathtt{bbababbbabaaaa} + dp(k)\),其中 \(k\) 為后面部分的第一對 \(a_k, b_k\) 的編號。
所以只要求出以上兩類的結果就行,第 1 類可以預處理,第 2 類的開頭的字符串,可以直接掃一遍判斷。
時間復雜度為 \(\mathcal O (N^2)\),評測鏈接。
cf679E
注意到在可能的值域(約為 \({10}^{14}\))內,\(42\) 的次冪並不多,嘗試從這個角度考慮。
操作 3 比較棘手,解決的辦法是用線段樹維護當前值到下一個 \(42\) 的次冪的差值。
做操作時讓這個差值做區間減法,在線段樹遞歸的時候,如果差值會變成負數,就需要再遞歸進子區間進行修改,但是如果這個區間被打上了區間覆蓋標記,就直接修改這個標記就行。
執行完后,如果存在差值為 \(0\) 的位置,就再執行一次。
這個做法的復雜度,使用勢能函數可以分析得出為 \(\mathcal O (q \log n \log_{42} v)\)。
具體地說,令當前線段樹的勢能函數等於每個值相同的連續段,比此連續段的值大的,在值域內的 \(42\) 的次冪的個數的總和,乘以 \(\log n\)。
則操作 2 和操作 3 的攤還代價都為 \(\mathcal O (\log n \log_{42} v)\)。
時間復雜度為 \(\mathcal O ((n + q) \log n \log_{42} v)\),其中 \(v\) 為值域,約為 \({10}^9 q\),評測鏈接。
2020-02-28
agc039_e
令 \(n = 2 N\),枚舉第 \(n\) 個點和哪個點連了,假設為 \(k\),即:
就分成了 \(1 \sim (k - 1)\) 和 \((k + 1) \sim (n - 1)\) 兩段。
直接考慮如果是區間 \([i, j]\),且這區間中的一點 \(k\) 與區間外的一點連線了,即:
如果 \(i < j\),那么被 \(k\) 分割的左右兩邊必然要通過至少一條線與 \((? \leftrightarrow k)\) 連接起來
但是又不能交叉,如果交叉就形成環了,所以取最上方的一條線 \((x \leftrightarrow y)\)。
所謂最上方,形式化地說就是 \(x\) 最靠近 \(i\),\(y\) 最靠近 \(j\)。
那么,\(x, y\) 在兩邊必然就會有各自的“管轄范圍”。
(你可以理解成,從 \((? \leftrightarrow k)\) 和 \((x \leftrightarrow y)\) 的交點出發向 \(x\) 或 \(y\) 方向走,能遍歷到的區域,它和其它區域不相交)
假設這個范圍分別為 \([i, p]\) 和 \([q, j]\)。
那么如果我們枚舉 \(i, j, k, x, y, p, q\)(滿足 \(i \le x \le p < k < q \le y \le j\)):
就可以轉化成三個子問題 \([i, p](x)\) 和 \([p + 1, q - 1](k)\) 和 \([q, j](y)\)。
可以在 \(\mathcal O (n^7)\) 的復雜度內解決此問題,因為常數大約是 \(1 / 7! = 1 / 5040\),所以其實是可以過的。
不過可以繼續優化,可以發現 \([i, p]\) 和 \([q, j]\) 是和 \(k\) 獨立的,也就是如果 \([i, j]\) 固定,\(k\) 的位置不影響 \(p, q\) 的選擇。
那么我們考慮先枚舉 \(p, q\),得到 \([i, p] \circ [q, j]\) 這個子問題,再在子問題里枚舉 \(x, y\)。
則處理所有 \([i, q] \circ [q, j]\) 就可以做到 \(\mathcal O (n^6)\) 的復雜度(枚舉 \(6\) 個變量)。
外層的 \([i, j](k)\) 就可以只枚舉 \(p, q\) 進行轉移,這部分復雜度為 \(\mathcal O (n^5)\)。
總時間復雜度為 \(\mathcal O (n^6)\),同樣帶了一個 \(1 / 6! = 1 / 720\) 的常數。
不過可以繼續優化,現在復雜度瓶頸是在 \([i, p] \circ [q, j]\) 這里,需要枚舉 \(x, y\) 才能轉移。
如果只枚舉一個 \(y\) 呢?
那就需要求 \([i, p]\) 區間中的,從 \(y > p\) 連進來一條邊的方案數,用記號 \([i, p]\{y\}\) 表示。
當然還有本來就要求的 \([q, j](y)\),這個是舊的東西了。
那么考慮計算 \([i, p]\{y\}\),這時就可以枚舉具體是和哪個 \(i \le x \le p\) 連邊,然后直接加上 \([i, p](x)\) 即可。
所以處理所有 \([i, p]\{y\}\) 的復雜度為 \(\mathcal O (n^4)\),而處理所有 \([i, p] \circ [q, j]\) 的復雜度降為 \(\mathcal O (n^5)\)。
總時間復雜度為 \(\mathcal O (n^5)\),帶了一個 \(1 / 5! = 1 / 120\) 的常數,評測鏈接。