實在有必要單獨拿出來說說,我一直認為我的計數能力相較其他能力是較突出的,但是最近做到的題目讓我不得不懷疑我到底會不會做計數題。做計數時還是隻能靠靈光一現嗎?那這樣的題目叫我怎麼靈光一現?
所以有必要好好總結計數題的常見技巧。當然因為樣本量有限,所以可能會漏掉某些重要的技巧。
從 2024 年 07 月開始,遇到計數題目就會嘗試更新本文。
上次更新是 2024年 08 月。
等價關係
如果遇到一個看起來就很難在合法的時間複雜度內透過的限制,那麼首先要做的就是找到原題目限制的等價條件。「AHOI2022」山河重整 是典型例子之一,原題目的條件似乎只能二維記錄,但是直覺上來說這個條件感覺不滿足的情況也比較單一。嘗試 \(O(n^2)\) 的 DP 時可以發現等價條件,那麼就可以針對不滿足的情況容斥就好了。
另一個找等價條件的題目是 「2021 集訓隊互測」這是一道集訓隊胡策題。等價條件的妙用是解決這個題目的關鍵,發現滿足原本的條件當且僅當 \(\sum_{i,j} ([a_i=c_{i,j}]+[b_j=c_{i,j}]-[a_i=b_j])=n^2\) 且其他情況一定有小於關係,於是只需要考慮取最大值的個數即可。
因此尋找等價條件的原則應該是讓問題更可做。
而等價條件的尋找就要因題而異了,一般來說是對於某個模型或者某種特殊的性質有固定的處理思路,在這些處理上找到題目限制帶來的特殊性。
唯一表示/最小表示
如果在條件的限制之下某幾種類似的情況只會被計入一次,那麼就考慮使用一種唯一的表示方法,比如最小表示,字典序最小,和最小,第一次出現的時候統計等等,因題目而異。
對映(雙射)關係
一個問題的方案,可以透過構造或者對映的方式一一對應另一個問題的方案,或者互不相交地拆成幾個不同的情況,或者相交的部分可以容斥掉。
典型的例子是透過 dp 的值反推原本的值。
比如如果有 \(f(i,j)=\max\{f(i-1,j),f(i,j-1)\}+a_{i,j}\),那麼就可以透過 \(f(i,j)\) 反推出 \(a\),對 \(f\) 計數就可以等效於對 \(a\) 計數,而且 \(f\) 一定滿足 \(f(i,j)\le f(i+1,j),f(i,j+1)\) 這一良好的性質。
對應的題目是 QOJ #2568. Mountains,是 LGV 引理的經典問題。以及加強版 QOJ #3082. Ascending Matrix 使用插值求出答案。
而且其實很多定理的證明也用到了雙射的原理。
就拿 LGV 引理舉例子。
針對不同情形的通常處理
對序列個數計數
如果條件只限制在相鄰元素之間,那麼就可以考慮透過插入並維護狀態的方式來計數,通常來說就成了連續段 dp 的板子題目。
但是會存在一些限制,不能輕易地在 dp 上表示。這時可以考慮插入的順序是否有特殊的地方。
比如 「2020-2021 集訓隊作業」Tour 此題(\(a_i\ge 0\) 的情況),透過合適的順序選取,可以使得 \(x\) 被插入時未被插入的元素要麼全部能插入在它的旁邊、要麼全部都不能插在它的旁邊。那麼對空位計數就可以了。
如果條件沒有限制在相鄰元素之間,那麼如果沒有轉化成其他型別的問題,那麼通常就需要 dp 來解決了。
有時還會考慮單調佇列、單調棧等。
對樹的個數計數
通常是矩陣樹定理吧,但是偶爾會有記錄連通塊個數和一些資訊的 dp 存在,其他情況就只能說是因題而異了(汗)。
棋盤問題
首先應該考慮橫縱座標能否分離。
如果不能將橫座標和縱座標分離,那麼可能思路就會比較有限了。此時就應該考慮棋盤的性質,比如滿足相鄰連邊後為二分圖,或者是平面圖,以及諸如此類的性質。
計數方式的最佳化和技巧
動態規劃
設計狀態
有些時候合理的狀態設計可以最佳化掉很多時間,最簡單的比如如果 \(f(i,j,k)\) 中只會用到 \(k-j\),那麼就沒必要記錄 \(f(i,j,k)\) 而可以只記錄 \(f(i,t=k-j)\) 就可以了。更多的例子因題而異
後置計數過程
有時如果說在每個時刻都要要求 \(f(i,\cdots)\) 的值就等於當前狀態下的方案數,那麼狀態數會特別複雜。或者某個時候我們需要直到後續的狀態來計算這個位置的貢獻,這時會很頭痛(當然也可以使用下面的欽定後續來做)。但是如果能夠在某個時刻我們再進行“清算”,一般這個時候會比較特殊,可以透過較少的幾個狀態的值推出方案數,就可以得到較少狀態的 dp 轉移方程。值得一提的是,如果這個“清算時刻”的量級比通常轉移的量級小,那麼在這個時刻,我們還可以支援更高時間複雜度的計算和轉移。
欽定後續(未來形 dp)
如果依次轉移的 dp 計數時會受到後續的影響,可以欽定後續的狀態為確定值,在轉移途中透過一個個確定的位置對這個值進行回溯,合法的情況最終會回溯到一個合法的初始值(所有不合法的初始值都不能回溯到初始值,否則就要容斥了)。
矩陣樹定理
\(D\) 為度數矩陣,\(A\) 為鄰接矩陣,\(M_i\) 為 \(D-A\) 去掉第 \(i\) 行第 \(i\) 列的矩陣,記原圖生成樹個數為 \(C\)。則有:
某引理最佳化矩陣樹定理
考慮矩陣 \(A\) 可逆時有以下等式:
因此得到 \(A\) 可逆時有 \(\det (A+UV^T)=\det A\det (I+V^TA^{-1}U)\) 成立。
那麼放在矩陣數定理上容易度數矩陣 \(D\) 和鄰接矩陣 \(A\) ,想到如果可以將 \(A\) 表示成 \(UV^T\),則有 \(\det (D-A)=\det D\det(I-V^TD^{-1}U)\) 成立。
構造更小的 \(U,V\),嘗試縮小 \(V^T D^{-1} U\) 即可。
經典題目:AGC060F
LGV 引理(平面圖前提下的組合意義)
如果有 \(n\) 個起點和 \(n\) 個終點各自排成一列為 \(s_i\) 和 \(t_i\),且整張圖為一個有向無環圖。
構造矩陣 \(M\) 使得 \(M_{ij}=w(s_i,t_j)\),其中 \(w(s_i,t_j)\) 表示所有從 \(s_i\) 出發到達 \(t_j\) 的路徑上邊權乘積之和。
如果原圖為平面圖,有 \(n\) 條路徑 \((s_i\to t_i)\),每條路徑之間沒有交,稱這個路徑組合法,且權值為這些路徑上所有邊的乘積。\(\det M\) 應該為所有合法路徑組的權值之和。
如果不是平面圖,則是一個沒什麼用的圖論中的計數意義。
容斥
轉移中容斥
這種方式一般會對應較為巧妙的計數題目。比如要求一個位置要麼滿足 \(A\) 性質,要麼滿足 \(B\) 性質,那麼轉移中可以欽定該位置滿足 \(A\) ,並轉移;欽定該位置滿足 \(B\),並轉移。但是發現從這裡轉移出去的情況中可能會有該位置既滿足 \(A\) 又滿足 \(B\) 的情況,這時可以欽定該位置同時滿足兩個性質並轉移 \(-2\) 倍。
更多的性質也是同理。
最終清算時容斥
就是最經典的容斥了。很多計數題目都有用。
實際上是反演的容斥
會放在反演類中單獨提到。
反演
二項式反演
通常運用於滿足以下條件的情況:個體之間獨立存在是否滿足條件的要求,即一個個體是否滿足條件不會影響其他個體是否滿足;任意相同個數的個體集合全部滿足條件的方案數相等;任意相同個數的個體集合全部不滿足條件的方案數 僅有 1 種。比如 \(F(m)\) 的意義是隻考慮 \(m\) 個個體,且這 \(m\) 個個體均滿足條件的方案數,\(f(n)\) 的意義是隻考慮 \(n\) 個個體,不對於這 \(n\) 個個體作其他要求時的方案數。那麼顯然有 \(f(n)=\sum_{m=0}^n {n\choose m} F(m)\),反演可得 \(F(m)=\sum_{n=0}^m{m\choose n} (-1)^{n+m} f(n)\),通常來說 \(f(n)\) 是好求的。
那麼問題來了,現在我認為這樣一個條件太侷限了,顯得整個反演很菜,感覺沒什麼用:“任意相同個數的個體集合全部不滿足條件的方案數 僅有 1 種”。假如我認為,一個個體有兩種方式不滿足條件,也就是說 \(n\) 個個體構成的集合全部不滿足條件的方案有 \(2^n\) 種時,二項式反演能否繼續給力?實際上是可以的:
這樣就皆大歡喜了,把 \(\frac{f(n)}{2^n}\) 和 \(\frac{F(m)}{2^m}\) 當作新的 \(f(n)\) 和 \(F(m)\) 即可。
另外還有三個二項式反演的變體,四者是類似的:
多項式科技最佳化二項式反演
對於 \(f(x)\) 和 \(F(x)\),設滿足 \(f(n)=\sum_{m\le n} {n\choose m} F(m)\)。
則應該有:
我們可以透過 \(f(0),f(1),\cdots,f(n)\) 快速求出 \(F(0),F(1),\cdots, F(n)\) 的值。
因為 \(F(x)\) 在只考慮 \(x=0,1,\cdots,n\) 時等效於一個 \(n\) 次多項式,因此我們可以認為:
考慮 \((-1)^x F(x)\) 的下降冪多項式形式其實就是上式。
眾所周知,對於多項式 \(g\):
注意第二個式子並非下降冪多項式形式,而是把下降冪多項式形式下的係數當作普通多項式形式下的係數進行卷積。那麼讓 \(g(x)=(-1)^x F(x)\)
而我們發現 \(g_m=\frac{(-1)^m f(m)}{m!}\)。所以直接普通多項式乘法就可以求出 \(g(0),g(1),\cdots,g(n)\),進而求出 \(F(0),F(1),\cdots,F(n)\)。
目前已知的應用:「2020-2021 集訓隊作業」Tour
斯特林反演
\(S(n,i)\) 是第二類斯特林數,\(s(n,i)\) 是第一類斯特林數,\(c(n,i)=|s(n,i)|\)。
這兩類斯特林數具有優秀的組合意義。
\(c(n,i)\) 是長度為 \(n\) 的排列中輪換個數為 \(k\) 的排列個數,\(S(n,i)\) 是 \(n\) 個互相區分的元素分成 \(k\) 個互不區分的集合的方案數,\(s,c,S\) 都可以遞推 \(O(n^2)\) 求出。
舉一個最基礎的例子,存在不同元素之間的二元等價關係 \(R\),我們需要求出 \(f(n)\) 表示有多少種長度為 \(n\) 的序列使得兩兩元素均不滿足等價關係 \(R\)。
那可以記 \(g(n)\) 表示有多少種長度為 \(n\) 的序列,並不做其它限制。
而根據等價關係可以對序列的元素劃分等價類,因此列舉 \(i\) 表示序列中的元素可以劃分成 \(i\) 個等價類,則有:
然後進行反演,得到:
就可以進行計算了。