插頭dp?你說的是這個嗎?

好吧顯然不是......
所謂插頭dp,實際上是“基於連通性的狀態壓縮dp”的簡稱,最先出現在cdq的論文里面
本篇博客致力於通過幾道小小的例題(大部分都比較淺顯)來介紹一下這種思路清奇的dp是怎么回事
Part I 定義
何為插頭?
插頭實際上是一個代稱,代指兩個格之間的連通性
若dp的某一個狀態中,有某相鄰的兩個格子是聯通的(比如說處在同一條路徑上、被同一個矩形覆蓋blablabla),我們就認為這兩個格子之間有插頭
舉個栗子,格子(1,1)和格子(2,1)聯通,那么格子(1,1)就有一個下插頭,而格子(2,1)有一個上插頭,如下圖所示

每一個格子可以有的插頭數量隨着題目而變
對於一道用路徑覆蓋棋盤的題目(不相交不重疊的路徑)而言,每個格子最多有兩個插頭:這種情況下表示有一條路徑從這個格子的某一個插頭的那個方向進來,又從另一個插頭的那個方向出去了
例如一條回路的插頭表示:

何為輪廓線?
輪廓線就是一條分割線,分隔了dp已經覆蓋的狀態和暫未覆蓋的狀態,它是在插頭dp的棋盤模型中被定義的
插頭dp有兩種dp方式:逐行遞推和逐格遞推,其中逐行遞推因為在很多題目中狀態過多被棄用
當然也不是說逐行遞推就沒有用了, 但是本文主要講逐格遞推
逐格遞推中,輪廓線是這樣的:設當前正在遞推的格子是(i,j)
那么輪廓線就是一條從棋盤左邊界開始,沿着第i行的格子底部向右延伸至格子(i,j)的左下角,然后向上一格,再一直向右延伸到棋盤右邊界
輪廓線的長度是m+1,其中m是列數
對於插頭dp的棋盤模型,輪廓線上的不同插頭狀態就是dp的狀態,因此可以引出插頭dp棋盤模型的狀態定義:
定義$dp\left[i\right]\left[j\right]\left[S\right]$表示如下條件時,插頭dp的狀態:
當前逐格遞推到了第$i$行第$j$列的格子,輪廓線上方的插頭狀態為$S$,其中$S$的是狀態壓縮的
輪廓線的一個例子如下圖:

其中黃色格子是當前正在遞推(也就是正在從黃色格子左邊的那個格子往黃色格子轉移)的格子,紅色的就是輪廓線
輪廓線的上方有m個下插頭位置和一個右插頭位置
PART II 棋盤模型
棋盤模型是插頭dp的最常見(前幾年最喜歡考)的方法
大概考法就是給你一個比較小的棋盤(15*15左右?或者更大一點),上面可能有些格子是障礙,然后讓你用一些閉合路徑啊,哈密頓回路啊或者一些奇奇怪怪的形狀來覆蓋棋盤上的每一個格子
還有一種考法就是給每個格子賦一個權值,然后讓你找一條最優的回路或者路徑或者某特定形狀之類的
這一類題目有一個關鍵點:把輪廓線畫出來以后,輪廓線上方的會是一些完備的“題目要求的形狀”和一些“一頭扎到”輪廓線下面,也就是被輪廓線切割的形狀,而這些被切割的形狀在輪廓線上方的分布我們不清楚,但是我們可以用輪廓線上插頭的狀態來表示所有情形的和
舉個例子,現在有一條輪廓線,輪廓線上面有一些插頭。我們現在可能不知道輪廓線上面的情況具體是怎么樣的,但是我們根據這些插頭就能往下推下面的狀態
所以我們只要記錄這種插頭狀態下輪廓線上方的答案,然后往下推就好了
也就是說我們把一個需要dfs找覆蓋的問題轉化成了一個dp模型~
現在的問題就是,我們怎么表示輪廓線上方的插頭的狀態呢?
cdq在論文中為我們提供了一個比較好的通解——最小表示法
最小表示法是這樣的:對於一類插頭可以互相配對的dp問題,我們有以下結論:
設從左到右的四個插頭a,b,c,d,其中ac配對bd配對,而ab不配對:這種情況不可能存在
因此此時一定要么ab配對cd配對,要么ad配對bc配對
最小表示法,就是從左到右掃一遍所有插頭,並這樣操作:
如果這個插頭已經被標記過了,就跳過
如果沒有,設當前的插頭是第i個未標記的插頭
將所有當前插頭聯通的插頭標記為i,然后進入下一個插頭
這養的方法,由於插頭dp本身是基於連通性的,所以一定可行,但是缺點是其時間效率可能較低
因此,對於每一道題,我們在確定最小表示法可以的前提下,可以再多加探索一些別的方法
比如下面這道例題:URAL1519
這道題利用的就是括號序列
又比如這道題:BZOJ2331
這道題利用L形自身的性質定義了插頭(我甚至都不確定這道題最小表示法能不能用)
棋盤模型的例題很多,這里列舉一些供大家參考
HNOI2004 郵遞員
HDU1693 eat the trees
POJ1739 Tony's tour
ZJOI2009 多米諾骨牌 (這個准確來說不是插頭dp,但是如果只有要求跨越每一行的話可以插頭解決)
這些題目的寫法基本都是大同小易,都是共同的,很多題甚至可以用同一份代碼過掉
但是一定要多寫,因為這樣才能讓插頭dp真正熟記於心,同時處理不同的題目也能加深理解
PART III 直線模型
先鴿着......還沒學透
例題:NOI2007生成樹計數,GDKOI2018d1t4(大概?)
終於!終於!時隔八個月!博主終於打破了咕咕咕的記錄!我把NOI2007生成樹計數做了!
然后發現其實能講的不多......
基礎原理
我們知道,插頭dp的本質,是“基於連通性的狀態壓縮dp”
那么對於一類構造圖/回路/生成樹的題目,我們就可以以對一部分點或者邊的連通性的描述作為dp的狀態,然后進行轉移
舉個栗子:NOI2007生成樹計數
這道題目利用了給定的圖的邊的特性,推出了一個狀態樹比較少的dp,然后套進了矩陣快速冪里面做完。
注意這道題目同樣利用了最小表示法,又根據第二類斯特林數的理論得到總的狀態數很少
方法特性&&注意事項
這個模型的題目,代碼復雜度和討論復雜度和棋盤模型比起來會少很多,但是它的難點不在於這里
這個模型的難點在於構造出符合“無后效性”和“狀態不重復不遺漏”的dp狀態
同時,要注意到“輪廓線”的概念依然存在於直線模型中,只是它的存在被編輯成了其它的形式,例如上一道例題中的
最后,一定要熟記最小表示法的應用
PART IV 總結
插頭dp平時可以見到的題目比較少,但是這並不妨礙插頭dp成為眾多優秀的dp模型中最具有思維復雜度以及討論的美感的dp之一
考試中遇到插頭dp的概率不大
如果遇到了棋盤模型請謹慎開題,避免全場剛一道導致爆炸;
如果遇到了直線模型,請......結合具體問題分析吧【因為實在是變數很多】
最后,不要學習我把一個知識點咕咕咕了長達八個月的時間>_<
