矩陣快速冪優化DP
一篇比較初步的方法總結。
矩陣快速冪優化遞推最經典的應用是快速求斐波那契數列的某一項,由於過於簡單在這裡沒有什麼必要提。由此引申出一類和上面一樣單純地優化遞推過程的題目。經典題目如 跳房子link,用 \(f_x\) 代表跳到 \(x\) 的方案數,用 \(F_x\) 表示 \(f\) 的字首和,那麼根據定義有 \(f_x=F_{x-n-1}\),而 \(F_x=F_{x-1}+f_x\),所以綜合一下就是 \(F_x=F_{x-1}+F_{x-n-1}\),於是就可以用矩陣快速冪來做了。轉移矩陣是這樣的:
\[\begin{bmatrix} F_x\\F_{x-1}\\\dots\\F_{x-n} \end{bmatrix} = \begin{bmatrix} 1&0&\dots&1\\ 1&0&\dots&0\\ \dots&\dots&\dots&\dots\\ 0&\dots&1&0 \end{bmatrix} \times \begin{bmatrix} F_{x-1}\\F_{x-2}\\\dots\\F_{x-n-1} \end{bmatrix} \]然後就可以啦。由於 \(\forall i\in[n+1],F_i=1\)
另外一種比較常見的就是 AC 自動機上套用矩陣快速冪。P3041link 在 AC 自動機那篇文章中已經說過了,有另一道題也很不錯。
還有就是圖上 DP,常見形式是什麼求走了多少步之後能到達哪些點。CF576D 是比較樸素的那種,顯然把時間分成一些階段,對於每個階段的末尾求出哪些點可以到達,然後剩下的路程考慮在當前邊集的基礎上廣搜出最短路。這裡有一個 bitset 優化乘積的方法,程式碼如下:
struct node{bitset<N>a[N];}newone;
inline node operator *(node x,node y){
node an=newone;
for(int i=1;i<=m;i++)for(int j=1;j<=m;j++)
if(x.a[i][j])an.a[i]|=y.a[j];
return an;
}
自然有許多變式,一種是常見的給邊加權,一般而言權會比較小。此時就可以考慮拆邊,把一個點拆成一串點,相鄰的點有 \(1\) 邊,新點記為 \((x,p)\)。連一條 \(x\) 到 \(y\) 權為 \(w\) 的點可以轉化成連一條 \((x,0)\) 到 \((y,w-1)\) 的邊即可,然後就可以正常快速冪優化了。迷路link 是板子。WYC 差不多,不用多說。