矩阵乘法 学习笔记

djwj233

2020-10-06 10:20:48

Personal

## 矩阵乘法用来做什么 可以`加速递推`。 ## 矩阵乘法主过程 两个矩阵 $A$,$B$,分别为 $n\times m$,$m\times k$ 的矩阵。 设 $C=A\times B$,那么 $C$ 是 $n\times k$ 的矩阵,且: $$C_{i,j}=\sum\limits_{k=1}^{m} A_{i,k}\times B_{k,j}$$ 和 $\texttt{Floyd}$ 的转移式类似。 Code: (不带取模) ```cpp struct mat { ll a[5][5]; mat(){ memset(a,0,sizeof(a)); } mat operator*(const mat &c)const{ mat tmp; fo(i,1,2) fo(j,1,2) fo(k,1,2) tmp.a[i][j]+=a[i][k]*c.a[k][j]; return tmp; } }; ``` 单位矩阵的定义: $$\exists f_0,\ s.t.\ \forall \textit{matrix}\ A\ ,A\times f_0=A $$ 则 $f_0$ 被称为**单位矩阵**。 性质: - 单位矩阵中的数**除向右的对角线外**都是 $0$ - 而向右的对角线上的数都是 $1$ - 如一个 $3$ 阶的单位矩阵: $$f_0=\begin{bmatrix}1&0&0\\0&1&0\\0&0&1\\\end{bmatrix}$$ ## 矩阵与递推 - 设 $A_0$ 为**初始矩阵**,即在 $A_0$ 中存有初始值 - 设 $A_n$ 保存着递推 $n$ 次后的矩阵。 - 设 $f$ 为**转移矩阵**,则有 $A_0\times f^n=A_n$ 如斐波那契数列中 $$\forall n\in \mathbb{N^+}\ , fib_n=\begin{cases}1&1\leq x\leq2\\ fib_{n-1}+fib_{n-2}&x\geq3\end{cases}$$ 则有: $$A_0=\begin{bmatrix}fib_1&fib_2\end{bmatrix}$$ $$A_n=\begin{bmatrix}fib_{n+1}&fib_{n+2}\end{bmatrix}$$ $$f=\begin{bmatrix}0&1\\1&1\end{bmatrix}$$ ## 矩阵的设计 重点!(敲黑板) 转移矩阵**每一列**便是下一矩阵该数所对的递推式。 如上例中 $f$ 矩阵 第一列的 $\begin{bmatrix}0\\1\end{bmatrix}$ 代表 $$(A_n)_{1,1}=0\times(A_{n-1})_{1,1} +1\times (A_{n-1})_{1,2}$$ 即: $$fib_{n+1}=0\cdot fib_n+1\cdot fib_{n+1}$$ 第二列的 $\begin{bmatrix}1\\1\end{bmatrix}$ 代表 $$(A_n)_{1,2}=1\times(A_{n-1})_{1,1} +1\times (A_{n-1})_{1,2}$$ 即: $$fib_{n+2}=1\cdot fib_n+1\cdot fib_{n+1}$$ ## 矩阵快速幂 那么得出 $$fib_n=A_0\times f^{n-2}$$ 暴力计算即可 $\Theta(n)$ 地解决此题。 好像暴力递推复杂度也一样,体现不出优势。怎么办呢? 我们发现后面这个 $f^{n-2}$ 可以快速幂,这样就可以 $\Theta(\log n)$ 地求解了。 ## 模板 - [P1962 斐波那契数列](https://www.luogu.com.cn/problem/P1962) 远古代码,码风见谅 ```cpp #include<bits/stdc++.h> using namespace std; #define fo(v,a,b) for(int v=a;v<=b;v++) #define fo2(v,a,b) for(v=a;v<=b;v++) #define fr(v,a,b) for(int v=a;v>=b;v--) #define fe(v,a) for(int v=head[a];v;v=Next[v]) #define rg register #define il inline const int p=1000000007; int a[3][3],f[3][3];long long n;//k-1,k int c[3][3]; void mul() { memset(c,0,sizeof(c)); fo(i,1,2) fo(j,1,2) fo(k,1,2) c[i][j]=(c[i][j]+(long long)a[i][k]*f[k][j])%p; fo(i,1,2) fo(j,1,2) a[i][j]=c[i][j]; } void mulself() { memset(c,0,sizeof(c)); fo(i,1,2) fo(j,1,2) fo(k,1,2) c[i][j]=(c[i][j]+(long long)f[i][k]*f[k][j])%p; fo(i,1,2) fo(j,1,2) f[i][j]=c[i][j]; } int main() { cin>>n; a[1][1]=a[1][2]=1;//k=2 f[1][2]=f[2][1]=f[2][2]=1; if(n==1LL)n=0LL; else n-=2LL; while(n) { if(n&1LL)mul(); mulself();n>>=1; } printf("%d\n",a[1][2]); return 0; } ``` ## 常用技巧 - [P1397 [NOI2013]矩阵游戏](https://www.luogu.com.cn/problem/P1397) 矩阵乘法依然满足 >1. 结合律 >1. 分配律 - [P6190 [NOI Online #1 入门组]魔法](https://www.luogu.com.cn/problem/P6190) 跑一遍 $\mathtt{Floyd}$ 求单次。 再将矩阵乘法中的运算**下移**: 1. $a+b$ --> $\max(a,b)$ 1. $a\times b$ --> $a+b$ 同时,下移后的运算也满足: >- $\max$ 交换律 > >- $\max$ 结合律 >- 加法交换律 >- 加法结合律 >- 加法分配律 - [P1707 刷题比赛](https://www.luogu.com.cn/problem/P1707) 码量极大,懒得写了QAQ - [CF1182E Product Oriented Recurrence](https://www.luogu.com.cn/problem/CF1182E) 初看此题,觉得无从下手。 ~~实际上想了一会儿还是无从下手~~ 面对这种不按套路的乘法递推,可以采用幂的形式统计次幂数,化乘为加。 本题中,先把的次幂提出: 设 $f_n=c^{X_n}\cdot {f_1}^{a_n}{f_2}^{b_n}{f_3}^{c_n}$ 那么 $\forall n\in \mathbb{N^+}\ ,$ $$X_n=\begin{cases}0&1\leq x\leq 3\\ X_{n-1}+X_{n-2}+X_{n-3}+(2n-6)&x>3\end{cases}$$ $$a_n=\begin{cases} 1&x=1\\ 0&2\leq x\leq 3\\ a_{n-1}+a_{n-2}+a_{n-3}&x>3\end{cases}$$ $$b_n=\begin{cases} 1&x=2\\ 0&1\leq x\leq 3\ \land x\ne 2 \\ b_{n-1}+b_{n-2}+b_{n-3}&x>3\end{cases}$$ $$c_n=\begin{cases} 1&x=3\\ 0&1\leq x\leq 2\\ c_{n-1}+c_{n-2}+c_{n-3}&x>3\end{cases}$$ 然后就可以矩乘了。 $a,b,c$ 设计矩阵时可以直接将前几项包含进去,然而 $X$ 不行。 怎么办呢? 可以添几个辅助项,像这样: $$A_n=\begin{bmatrix}X_n&X_{n-1}&X_{n-2}&n&1\end{bmatrix}$$ 其中 $1$ 是不变的, $n$ 是每次加一的。 每次的 $2n-6=2(n-1)-4$ 则有: $$A_0=\begin{bmatrix}0&0&0&3&1\end{bmatrix}$$ $$f=\begin{bmatrix} 1&1&0&0&0 \\1&0&1&0&0 \\1&0&0&0&0 \\2&0&0&1&0 \\-4&0&0&1&1 \end{bmatrix}$$ 这样计算出 $a_n,b_n,c_n,X_n$,套用快速幂即可。 - [P3758 [TJOI2017]可乐](https://www.luogu.com.cn/problem/P3758) 图论题。 定义 $dp_{i,j}$ 为在 $i$ 时刻,目前位于 $j$ 的方案数。 设 $S(i)$ 为与 $i$ 直接相连的点的集合(包括 $i$ 自己)。 则有: $$dp_{0,1}=1,dp_{0,x}=0\ (x\neq 1)$$ $$dp_{t,i}=\sum\limits_{j\in S(i)}dp_{t-1,j}$$ 然后我们发现转移固定,可以采用矩阵优化。 一般地,在一张已确定的,$n$ 不大的图上进行 $t$ 很大的转移,可以用矩阵进行优化。 如 :[P6772 [NOI2020]美食家](https://www.luogu.com.cn/problem/P6772) 边权不为 $1$,但很小。于是采用了拆点的形式转移。 - [P1357 花园](https://www.luogu.com.cn/problem/P1357) 有点难的状压DP,有空做。