D1T1
考慮朴素 DP:設 \(f_{i,j}\) 表示恰好在時刻 \(i\) 停留在 \(j\) 號城市的最大美味值。發現 \(w \leq 5\) 故 \(f_i\) 只取決於 \(f_{i-5 \sim i-1}\),將 \(f_{i-5 \sim i-1}\) 壓成行向量之后不難在 \((\max , +)\) 意義下寫出一個矩陣滿足這個行向量乘上這個矩陣得到 \(f_{i-4 \sim i}\) 壓成的行向量。那么 \(k=0\) 的情況直接矩陣快速冪,\(k \neq 0\) 的情況按照時間排序之后依次求出每一個美食節時刻的 \(f\) 值然后對美食節城市加上美食節權值即可。注意預處理出轉移矩陣的冪並且在向量乘矩陣時使用 \(O(n^2)\) 做法,可以做到 \(O((5n)^2(5n+k) \log T)\) 復雜度。
D1T2
考慮一個 DP:設 \(f_{i,j}\) 表示做完了 \(i\) 及 \(i\) 的子樹,所有靠下的點在 \(i\) 子樹內、鏈在 \(i\) 子樹內的部分沒有被任何一條重要邊覆蓋的鏈的靠上的點的深度的最大值為 \(j\) 的方案數,\(j=0\) 表示不存在這樣的鏈,\(j \geq dep_i\) 的狀態非法。答案就是 \(f_{1,0}\)。
轉移時先考慮從兒子合並。合並 \(f_i\) 和 \(f_{son}\) 時,設轉移完成后 \(i\) 點 DP
值為 \(f'_i\),枚舉 \(p,q\) 有轉移 \(f'_{i,\min\{p,q\}} \leftarrow f_{i,p} \times f_{son,q}\)。在轉移完成之后,可以選擇 \(i\) 到父親的邊設為黑邊或者不設為黑邊有一個轉移,然后把非法狀態的 \(f\) 值清空。復雜度可以用后綴和優化為 \(O(n^2)\)。
優化的主要考慮是 \(f_i\) 有很大一部分是 \(0\)。考慮使用數據結構維護不是 \(0\) 的位置,可以發現以上操作可以使用線段樹合並解決。復雜度 \(O(n \log n)\)。
D1T3
首先肯定不能 polylog。對序列分塊,零散塊的貢獻容易在單次 \(O(\sqrt{n})\) 內計算。
然后考慮容斥,把答案變為三個部分:位置 \([l,r]\) 值域 \([1,R]\) 的順序對數、位置 \([l,r]\) 值域 \([1,L-1]\) 的順序對數、位置 \([l,r]\) 一個值域 \([1,L-1]\) 一個值域 \([L,R]\) 的順序對數。算出三者之后可以拼出答案。
對於前兩個部分,離線后對值域右端點排序並掃描線。掃描線向右移一格相當於加入了一個新點,且這個點一定是最大的。設 \(f_{i,j}(i \geq j)\) 表示在當前掃描線狀態一個數在第 \(i\) 塊另一個數在第 \(j\) 塊的順序對數量,加入一個數時通過維護當前每個塊中被掃入的數的數量可以做到 \(O(\sqrt{n})\) 更新。對於一組詢問則是一個矩形求和,因為矩形邊長只有根號,所以對 \(j\) 一維做前綴和之后暴力枚舉 \(i\) 維取值可以 \(O(\sqrt{n})\) 求答案。
對於第三個部分,最重要的點是兩個不同的塊之間的貢獻容易計算,就是靠前的塊中值域在 \([1,L-1]\) 內的數的數量 \(\times\) 靠后的塊中值域在 \([L,R]\) 內的數的數量。
從左往右掃描每一個塊,掃到某一個塊時維護前面所有的塊中值域在 \([1,L-1]\) 的數的數量和,乘上當前塊中值域在 \([L,R]\) 的數的數量即可得到塊間貢獻。塊內貢獻對每個塊離線之后可以發現每個塊只有 \(O(n)\) 種本質不同的答案,因為答案和值域關系不大,只和 \(L-1,R\) 在塊中的大小排名有關。對於一個塊可以容易地在 \(O(n)\) 時間內求出所有可能的答案和所有數的排名,這一部分就可以做到 \(O(n \sqrt n)\)。
總復雜度 \(O((n+q)\sqrt{n})\),比 \(O((n+q)n^{\frac{2}{3}})\) 難寫到不知道哪里去了,常數感覺比一般的分塊要優。
D2T1
首先一個容易歸納證明的結論是如果 \(i\) 個食材的總重量為 \(tk(t \geq i-1)\) 那么一定可以做 \(t\) 道菜,證明考慮重量最小的和最大的食材總能做一道菜,然后盡可能減少食材的數量。
對於 \(m=n-2\) 容易證明如果存在方案則總存在一個食材的子集滿足如果這個子集的大小為 \(i\) 那么總重量為 \((i-1)k\)。將所有食材的重量 \(-k\) 就相當於選擇一個子集重量和為 \(-k\)。這顯然是個背包問題,使用 bitset 優化背包,倒推還原方案,倒推時暴力枚舉可能的前驅即可。復雜度 \(O(\frac{Tn^2k}{w})\)
D2T2
考慮一個分治算法:設 \(solve(T)\) 表示判斷樹集合 \(T\) 是否幾乎完備,分治的核心思想是考慮所有樹集合 \(T\) 無法表示的樹在根上的兒子長什么樣,內容如下。
- 如果 \(T = \varnothing\) 則答案為
No
; - 如果一個點的樹被 \(T\) 包含則答案為
Almost Complete
; - 在上面兩種比較 Trivial 的情況判定完成之后考慮枚舉表示不出的樹的根的子樹。如果這些樹的根只有左兒子,那么 \(T\) 中只有那些只有左兒子的樹有可能生長得到它。故取出 \(T\) 所有僅有左兒子的樹的左子樹集合 \(T_l\),如果 \(T_l\) 是不完備的,那么 \(T\) 顯然是不完備的。同理定義 \(T_r\)。
- 然后考慮有兩個子樹的情況。先考慮根的左子樹。取出所有有兩個子樹的樹的左子樹集合 \(T_l'\),如果存在一棵樹不能被 \(T_l'\) 生長得到,那么在左子樹選擇這棵樹的情況下右子樹任意選擇都無法被生長得到,那么當前集合顯然不是幾乎完備的,也就是說 \(T_l'\) 是完備的。不難證明 \(T_l'\) 完備的充要條件是 \(T_l'\) 包含一個點的樹,同理 \(T_r'\) 也包含只有一個點的樹。同時注意到一個點的樹可以生長得到所有的樹,所以考慮所有左子樹為一個節點的右子樹集合 \(T_r''\),如果 \(T_r''\) 不是幾乎完備的,則原集合顯然不是幾乎完備的;同理定義 \(T_l''\),如果 \(T_l''\) 和 \(T_r''\) 都是幾乎完備的,那么只有有限多個左子樹滿足存在有限多個右子樹它們拼起來無法生長得到,顯然只有有限多個樹不能被生長得到,整個就是幾乎完備的。
這樣就判斷了所有情況,代碼很簡單,判斷了 12 之后遞歸 \(T_l,T_r,T_l'',T_r''\) 就完了。
D2T3
不會