P9522 [JOISC2022] 錯誤拼寫
牛魔計數題使我旋轉。
主要說一下分析思路:
根據字典序的比較方式我們可以轉化一下 \(T_{A_j}<T_{B_j}\) 這個條件。我們現在只考慮嚴格小於的情況。
字典序暗示我們要從後往前 DP,於是設 \(f_{i,j}\) 表示 \(s_i=j\) 的方案數。然後考慮從 \(f_{i',j'}\) 轉移過來,思考轉移的約束。
這個約束就是對於一段 \([A,B]\) 裡面的 \(i'\),對 \(i<A\) 都要少掉一段貢獻,這段貢獻和 \(j\) 有關。
於是設 \(h_j\) 表示 \(i+1\sim n\) 中 \(f_{*,j}\) 的貢獻。每次移動 \(i\) 的時候更新 \(h_j\)。用連結串列維護,時間複雜度 \(\mathcal{O}(n|\sum|)\)。
計數題好難。
P2051 [AHOI2009] 中國象棋
即每一行、每一列最多有兩個棋子。
在轉移的時候,我們需要依賴於上一層的狀態,但往往我們無需清楚每個地方的狀態具體是啥,只需知道某種狀態的個數,然後使用排列組合計算。
設 \(f_{i,j,k}\) 表示前 \(i\) 行,有 \(j\) 列一個炮,有 \(k\) 列兩個炮。
列舉這一行放幾個炮直接轉移就行。
P3158 [CQOI2011] 放棋子
發現維護個數比較困難。
發現每種顏色都是相互獨立的,區域的劃分依據是完整的行和列。所以可以考慮設 \(f_{k,i,j}\) 表示前 \(k\) 種顏色佔據了 \(i\) 行 \(j\) 列的方案(這類題通常都可這樣設),轉移需要一個 \(g_{i,j,k}\) 表示用 \(k\) 枚同色棋子佔據 \(i\) 行 \(j\) 列的方案。
\(g\) 需要容斥。
P10982 Connected Graph
正難則反,我們求 \(n\) 個點的無向不聯通圖個數。
一開始為了不計算重複,我設了 \(f_{i,j}\) 表示 \(i\) 個點,形成 \(j\) 個聯通塊的方案,然後再它做容斥,但總有點問題。
一種可行的方法是:欽定一個點作為劃分依據。
比如以 \(1\) 號點為依據,設 \(f_i\) 表示 \(i\) 個點的聯通圖方案,轉移時考慮 \(1\) 號點所在聯通塊大小,讓其餘的點不與該聯通塊連邊即可。
CF1989E Distance to Different
觀察到 \(b\) 取決於 \(a\) 中相同陣列成的連續段。
設 \(f_{i,j}\) 表示前 \(i\) 個數分成了 \(j\) 個連續段的大小,轉移不表,注意要特殊處理 \(f_{i-2,j-1}\)。
我想到這後還一直在想怎麼保證每種數都填進去了這 \(j\) 個段,後來才發現只需保證分成了至少 \(k\) 個段就行了,具體怎麼填根本不重要,因為對應的 \(b\) 都是一樣的。
所以第二維只用開到 \(k+1\),字首和最佳化。
自己實在太唐了。
CF1585F Non-equal Neighbours
感覺要記錄 \(i\) 選的數和 \(a_i\) 的大小關係。然後可能可以轉移??貌似沒人這樣做。
考慮容斥,欽定有 \(k\) 個 \(i\) 滿足 \(b_i=b_{i+1}\),則 \(ans=\sum\limits_{k=0}^{n-1}(-1)^kF(k)\)。
於是有一個樸素的 DP,設 \(f_{i,j}\) 表示前 \(i\) 個數,分成了 \(j\) 段的方案數,時間複雜度 \(\mathcal{O}(n^3)\)。
然後發現我們需要的是段數的奇偶性,於是將狀態改為 \(f_{i,0/1}\),時間複雜度 \(\mathcal{O}(n^2)\)。
發現轉移式裡不好最佳化的是一個 \(\min\),這個可以搞一個單調棧,然後加上一堆判斷搞定。
CF1909F Small Permutation Problem
很厲害的題。
先考慮 Easy Version。一開始編了一個 DP 做法,但好像不太對。
第一步轉化就是將 \((i,p_i)\) 放到座標系上,將問題轉化成放車問題,合法的放置要求每一行每一列都只有一個車。那麼 \(a_i-a_{i-1}\) 就對應著一個 L 字形裡的點對數量。實時維護 \((1,1)\sim(i,i)\) 還未放置的行列數量即可。
考慮 Hard Version,我們可以將一段 \(-1\) 縮起來,設區間 \((i,j)\) 之間全是 \(-1\),那麼相當於在一個 \(y\times y\) 的網格挖掉左下角 \(x\times x\) 的網格後形成的 L 字形網格中放 \(t\) 個車,其中 \(x=j-a_j\),\(y=i-a_j\),\(t=a_i-a_j\)。這個東西可以容斥。時間複雜度 \(\mathcal{O}(n)\)。
[ARC180C] Subsequence and Prefix Sum
發現 \(0\) 有很大的影響。發現第一個選的數也有很大影響(但這種可以歸類為前面那種,因為初始值為 \(0\))。
一旦字首和出現了 \(0\),後面如果只選一個數,那麼跟不選沒區別。如果選不止一個數,那麼第一個數要是相同的選哪個都一樣。怎麼辦?
一開始想用最小表示法,但不會 。
發現自己智力不夠,思維混亂,我們只需再記錄 \(g_i\) 表示前面和為 \(i\) 且上一次為 \(0\) 的方案數。然後我們不用 \(f_{i-1,0}\) 轉移到 \(f_{i,a_i}\),這樣就避免了選一個數的情況。然後用 \(g_j\to f_{i,j+a_i}\),就計算上了不止選一個數的情況。每次迴圈後,\(g_{a_i}\leftarrow g_0\),\(g_0\leftarrow f_{i,0}\)。
反思:思維混亂,在計數題中是大忌。要學會歸納各種情況,減少複雜的分類討論,規約為簡單的問題。
P9131 [USACO23FEB] Problem Setting P
先考慮狀壓出每道題的狀態,狀態相同的單獨考慮。然後思考轉化判定條件:其實就是滿足前一道題是後一題的子集。
那我們設 \(f_s\) 表示最後一道是 \(s\) 狀態的題,列舉子集直接轉移,時間複雜度 \(\mathcal{O}(3^m)\)。
一個 Trick:將狀壓後的數折半,分成前後兩部分。
設 \(s_{i,j}\) 表示滿足 \(x\) 前 \(10\) 位是 \(i\),後 \(10\) 位是 \(j\) 子集的 \(f_x\) 的總和。那麼轉移的時候只需列舉前 \(10\) 位,修改 \(s\) 時只需列舉後 \(10\) 位。可以做到 \(\mathcal{O}(n2^{m/2})\)。
有一個大神 DP:考慮最佳化列舉子集,考慮每次加入一個元素,按 \(|S|\) 轉移,從集合 \(i\to i\cup \{s_1,s_2,\dots,s_k\}\) 有 \(k!\) 種方式。
設 \(f_{i,j}\) 表示現在走到集合 \(i\),用了 \(j\) 步的方案。
- 下一步走到的集合不選:\(f_{i\cup \{x\},j+1}\leftarrow f_{i,j}\)
- 下一步走到的集合選:\(f_{i\cup\{x\},0}\leftarrow f_{i,j}\times \dfrac{1}{(j+1)!}\times val_{i\cup \{x\}}\)
反思:轉化判定條件,配合一些 Trick 的使用。