update in 9.17ide
并不想扯什么高端线代的内容由于我也不会函数
由$n \times m$个数$a_{ij}$排成的$n$行$m$列的数表称为$n$行$m$列的矩阵,简称$n \times m$矩阵。学习
$$
A =
\begin{bmatrix}
a_{11} & a_{12} & \dots a_{1m} \\
a_{21}, & \dots & \dots \\
a_{31}, & \dots & \dots \\
a_{41} & \dots & a_{nm}
\end{bmatrix}
$$优化
这里只讲加法减法和乘法,其余的例如矩阵求逆等与本文内容出入较大,有兴趣的能够本身学习spa
注意,只有行列均相同的矩阵才有加法!.net
运算也比较简单,把对应位置的数相加获得一个新的矩阵,即为答案code
例如blog
$$
\begin{bmatrix} 1 & 1 & 2 \\ 1 & 0 & 1 \end{bmatrix}
+
\begin{bmatrix} 2 & 3 & 3 \\ 3 & 3 & 2 \end{bmatrix}
=
\begin{bmatrix} 3 & 4 & 5 \\ 4 & 3 & 3 \end{bmatrix}
$$ip
加法知足如下运算律get
$A + B = B + A$
$(A + B) + C = A + (B + C)$
与加法同理。
这才是重点!!
两个矩阵能进行乘法的前提条件是:一个矩阵的行数等于另外一个矩阵的列数
形式化的来讲,若$A$是$i \times k$的矩阵,那么$B$必须是$k \times j$的矩阵!
他们相乘获得的$C$是$i \times j$的矩阵
其中$C_{ij} = \sum_{i = 1}^n A_{ik} * B_{kj}$
好比
$$
\begin{bmatrix} 1 & 2\\ 2 & 3 \end{bmatrix}
\times
\begin{bmatrix} 2 & 4 & 5 \\ 3 & 4 & 3 \end{bmatrix}
=
\begin{bmatrix} 8 & 12 & 11 \\ 13 & 20 & 19 \end{bmatrix}
$$
乘法知足结合律,左分配律,右分配律,即
$(A \times B) \times C = A \times (B \times C)$
$(A + B) \times C = A \times C + B \times C$
$C(A + B) = C \times A + C \times B$
千万注意!矩阵乘法不知足交换律!(不少状况下交换以后都不能相乘)
由于矩阵有结合律,所以咱们能够把整数的快速幂推广的矩阵上面
一样是利用二进制倍增的思想,不可贵到如下代码
其中的base,表明的是单位矩阵,也就是除了对角线全为$1$,其余位置都为$0$的矩阵,能够证实任意矩阵乘单位矩阵都等于自身
显然矩阵快速幂的复杂度为$O(n^3 log k)$
#include<cstdio> #define LL long long using namespace std; const int mod = 1e9 + 7; int N; LL K; struct Matrix { int m[101][101]; Matrix operator * (const Matrix &rhs) const { Matrix ans = {}; for(int k = 1; k <= N; k++) for(int i = 1; i <= N; i++) for(int j = 1; j <= N; j++) (ans.m[i][j] += 1ll * m[i][k] * rhs.m[k][j] % mod) %= mod; return ans; } }; Matrix fastpow(Matrix a, LL p) { Matrix base; for(int i = 1; i <= N; i++) base.m[i][i] = 1;//构造单位矩阵 while(p) { if(p & 1) base = base * a; a = a * a; p >>= 1; } return base; } int main() { scanf("%d %lld", &N, &K); Matrix a; for(int i = 1; i <= N; i++) for(int j = 1; j <= N; j++) scanf("%d", &a.m[i][j]); a = fastpow(a, K); for(int i = 1; i <= N; i++, puts("")) for(int j = 1; j <= N; j++) printf("%d ", a.m[i][j]); return 0; }
矩阵快速幂最多见的应用就是优化递推啦
仍是从最多见的斐波那契数列提及吧。
众周所知,斐波那契数列的递推公式为$$f_{n} = f_{n - 1} + f_{n - 2}, f_1 = 1, f_2 = 1$$
通常来讲,这种看起来长得很萌简单,只与自身的函数值有关(可能带几个常数)的式子,通常均可以用矩阵快速幂来加速。
固然,若是你想找刺激,能够学一下这玩意儿
矩阵快速幂具体是怎么加速递推的呢?
首先咱们把斐波那契数列写成矩阵的形式,由于$f_n$的取值与$f_{n - 1}, f_{n - 2}$这两项有关,所以咱们须要同时保留这两项的值,咱们不可贵到一个$2 \times 1$的矩阵
$$
\begin{bmatrix}
f_{n} \\
f_{n - 1}
\end{bmatrix}
$$
如今咱们要进行递推,也就是获得这样一个矩阵
$$
\begin{bmatrix}
f_{n + 1} \\
f_{n}
\end{bmatrix}
$$
展开
$$
\begin{bmatrix}
f_{n} + f_{n - 1} \\
f_{n}
\end{bmatrix}
$$
观察一下,上面的一项须要用到$f_{n}$和$f_{n - 1}$,下面的一项只须要用到$f_n$
同时结合上面的矩阵乘法的定义,咱们不可贵到一个转移矩阵
$$
\begin{bmatrix} 1 & 1 \\ 1 & 0 \\ \end{bmatrix}
\begin{bmatrix} f_{n} \\ f_{n - 1}\\ \end{bmatrix}
=
\begin{bmatrix} f_{n} + f_{n - 1} \\ f_{n}\\ \end{bmatrix}
$$
这样咱们乘一次便可递推到下一项。
可是这样好像并无什么卵用啊,复杂度上还多了个矩阵相乘
嘿嘿
不要忘了,咱们前面能够讲过矩阵有结合律的!
这样的话咱们只须要把转移矩阵自乘$n - 1$次,而后再与初始矩阵相乘,就能获得答案矩阵啦!
// luogu-judger-enable-o2 #include<cstdio> #include<cstring> #define LL long long using namespace std; const int mod = 1e9 + 7; LL K; struct Matrix { int m[101][101], N; Matrix() { memset(m, 0, sizeof(m)); N = 2; } Matrix operator * (const Matrix &rhs) const { Matrix ans; for(int k = 1; k <= N; k++) for(int i = 1; i <= N; i++) for(int j = 1; j <= N; j++) (ans.m[i][j] += 1ll * m[i][k] * rhs.m[k][j] % mod) %= mod; return ans; } }; Matrix fastpow(Matrix a, LL p) { Matrix base; for(int i = 1; i <= base.N; i++) base.m[i][i] = 1;//鏋勯€犲崟浣嶇煩闃? while(p) { if(p & 1) base = base * a; a = a * a; p >>= 1; } return base; } int main() { scanf("%lld", &K); Matrix a; a.m[1][1] = 1; a.m[1][2] = 1; a.m[2][1] = 1; a.m[2][2] = 0; a = fastpow(a, K - 1); printf("%d", a.m[1][1]); return 0; }
https://www.nowcoder.com/acm/contest/185/B
给出一个 n * n 的邻接矩阵A.A是一个01矩阵 .A[i][j]=1表示i号点和j号点之间有长度为1的边直接相连.求出从 1 号点 到 n 号点长度为k的路径的数目.
作法:直接对给出的矩阵快速幂$k$次,输出$A[1][N]$
解释:考虑矩阵相乘的过程,咱们对于要计算的$(i, j)$位置,咱们至关因而枚举了一个中间节点$k$,来计算$(i, k) * (k, j)$
$$G_i = a\times G_{i - 1} + b\times G_{i - 2}$$
\begin{equation*}
\begin{bmatrix}
a&b\\
1 & 0\\
\end{bmatrix}^{i - 1}\times
\begin{bmatrix}
G_{1}\\
G_{0}\\
\end{bmatrix}=
\begin{bmatrix}
a&b\\
1 & 0\\
\end{bmatrix}\times
\begin{bmatrix}
G_{i - 1}\\
G_{i - 2}\\
\end{bmatrix}=
\begin{bmatrix}
G_{i}\\
G_{i - 1}\\
\end{bmatrix}
\end{equation*}
$$G_i = a\times G_{i - 1} + i^2$$
\begin{equation*}
\begin{bmatrix}
a&1&0&0\\
0 & 1&2&1\\
0 & 0&1&1\\
0 & 0&0&1\\
\end{bmatrix}^{i}\times
\begin{bmatrix}
G_{0}\\
1\\
1\\
1\\
\end{bmatrix}=
\begin{bmatrix}
a&1&0&0\\
0 & 1&2&1\\
0 & 0&1&1\\
0 & 0&0&1\\
\end{bmatrix}\times
\begin{bmatrix}
G_{i - 1}\\
i^2\\
i\\
1
\end{bmatrix}=
\begin{bmatrix}
G_{i}\\
(i + 1)^2\\
i + 1\\
1
\end{bmatrix}
\end{equation*}
$$G_i = a\times G_{i - 1} + i^3$$
\begin{equation*}
\begin{bmatrix}
a&1&0&0&0\\
0 & 1&3&3&1\\
0 & 0&1&2&1\\
0 & 0&0&1&1\\
0 & 0&0&0&1\\
\end{bmatrix}^{i}*
\begin{bmatrix}
G_{0}\\
1\\
1\\
1\\
1\\
\end{bmatrix}=
\begin{bmatrix}
a&1&0&0&0\\
0 & 1&3&3&1\\
0 & 0&1&2&1\\
0 & 0&0&1&1\\
0 & 0&0&0&1\\
\end{bmatrix}\times
\begin{bmatrix}
G_{i - 1}\\
i^3\\
i^2\\
i\\
1
\end{bmatrix}=
\begin{bmatrix}
G_{i}\\
(i + 1)^3\\
(i + 1)^2\\
i + 1\\
1
\end{bmatrix}
\end{equation*}
$$G_i = a\times G_{i - 1} + b^i$$
\begin{equation*}
\begin{bmatrix}
a&1\\
0 & b\\
\end{bmatrix}^{i}\times
\begin{bmatrix}
G_{0}\\
b\\
\end{bmatrix}=
\begin{bmatrix}
a&1\\
0 & b\\
\end{bmatrix}\times
\begin{bmatrix}
G_{i - 1}\\
b^{i}\\
\end{bmatrix}=
\begin{bmatrix}
G_{i}\\
b^{i+1}\\
\end{bmatrix}
\end{equation*}