矩阵乘法怎么乘
设让矩阵 a a a 乘矩阵 b b b 得到矩阵 c c c,那么 c c c 的第 i i i 行第 j j j 个元素的值就等于 a a a 的第 i i i 行与 b b b 的第 j j j 列上对应元素相乘的和。
举个例子:
(
1
2
3
4
)
∗
(
4
3
2
1
)
=
(
a
b
c
d
)
\left( \begin{array}{c} 1 & 2 \\ 3 & 4 \end{array} \right) * \left( \begin{array}{c} 4 & 3 \\ 2 & 1 \end{array} \right)= \left( \begin{array}{c} a & b\\ c & d\\ \end{array} \right)
(1324)∗(4231)=(acbd)
那么对于
a
a
a 的值,就是第一个矩阵的第一行
(
1
,
2
)
(1,2)
(1,2) 和第二个矩阵的第一列
(
4
,
2
)
(4,2)
(4,2) 的对应元素相乘的和,也就是
a
=
1
×
4
+
2
×
2
=
8
a=1\times 4+2\times 2=8
a=1×4+2×2=8。
再比如
c
c
c 的值,
c
=
3
×
4
+
4
×
2
=
20
c=3\times 4+4\times 2=20
c=3×4+4×2=20
最后的结果是:
(
1
2
3
4
)
∗
(
4
3
2
1
)
=
(
8
5
20
13
)
\left( \begin{array}{c} 1 & 2 \\ 3 & 4 \end{array} \right) * \left( \begin{array}{c} 4 & 3 \\ 2 & 1 \end{array} \right)= \left( \begin{array}{c} 8 & 5\\ 20 & 13\\ \end{array} \right)
(1324)∗(4231)=(820513)
可以看出,得到的矩阵
c
c
c 的行数就是矩阵
a
a
a 的行数,列数就是矩阵
b
b
b 的列数。
矩阵乘法的限制
上面提到, c c c 的每一个元素都是矩阵 a a a 某一行与矩阵 b b b 的某一列元素对应元素的乘积的和,那么就有一个限制,就是 a a a 的行要能与 b b b 的列相对应,换句话说, a a a 的列数与 b b b 的行数要相同,否则是做不了矩阵乘法的。
矩阵乘法的性质
矩阵乘法不满足交换律,这个比较显然。
但是结合律和分配律还是满足的。(想想就明白了)
其他东西
矩阵乘法,其实也可以理解为向量乘向量,矩阵 a a a 乘矩阵 b b b,可以将 a a a 的每一行视为一个向量,这个向量的维度就是 a a a 的列数, b b b 的每一列是一个向量,维度为 b b b 的行数, a b ab ab 相乘得到的矩阵 c c c 其实就是 a a a 和 b b b 包含的向量两两的点积,所以要求 a a a 的列数与 b b b 的行数相同。
据说矩阵是为了给线性方程组一个更方便的表示方法,假如有这样一个线性方程组:
{
2
x
+
y
=
5
x
−
y
=
1
\begin{cases} 2x+y=5\\ x-y=1 \end{cases}
{2x+y=5x−y=1
用矩阵表示就是这个样子:
(
2
1
1
−
1
)
∗
(
x
y
)
=
(
5
1
)
\left( \begin{array}{c} 2 & 1\\ 1 &-1 \end{array} \right)* \left( \begin{array}{c} x\\ y \end{array} \right)= \left( \begin{array}{c} 5\\ 1 \end{array} \right)
(211−1)∗(xy)=(51)
用处:
可以用来加速方程的递推。
很经典的,
f
i
b
o
n
a
c
c
i
fibonacci
fibonacci 数列,
f
(
n
)
=
f
(
n
−
1
)
+
f
(
n
−
2
)
f(n)=f(n-1)+f(n-2)
f(n)=f(n−1)+f(n−2),那么发现要得出下一项的值的话只需要前两个数即可,那么可以先搞出下面这个矩阵:
(
f
(
x
−
1
)
f
(
x
−
2
)
)
\left( \begin{array}{c} f(x-1)\\ f(x-2) \end{array} \right)
(f(x−1)f(x−2))
那么,我们下一步,就是要把这个矩阵变成下面这个矩阵:
(
f
(
x
)
f
(
x
−
1
)
)
\left( \begin{array}{c} f(x)\\ f(x-1) \end{array} \right)
(f(x)f(x−1))
很显然,只需要让这个矩阵乘上原来的矩阵即可:
(
1
1
1
0
)
\left( \begin{array}{c} 1 & 1\\ 1 & 0 \end{array} \right)
(1110)
计算过程:
(
1
1
1
0
)
∗
(
f
(
x
−
1
)
f
(
x
−
2
)
)
=
(
f
(
x
)
f
(
x
−
1
)
)
\left( \begin{array}{c} 1 & 1\\ 1 & 0 \end{array} \right)* \left( \begin{array}{c} f(x-1)\\ f(x-2) \end{array} \right)= \left( \begin{array}{c} f(x)\\ f(x-1) \end{array} \right)
(1110)∗(f(x−1)f(x−2))=(f(x)f(x−1))
那么,要求
f
(
n
)
f(n)
f(n) 的话,只需要让
(
f
(
2
)
f
(
1
)
)
\left( \begin{array}{c}f(2)\\f(1)\end{array}\right)
(f(2)f(1))被乘
n
−
2
n-2
n−2 次
(
1
1
1
0
)
\left( \begin{array}{c}1 & 1\\1 & 0\end{array}\right)
(1110) 即可。
又因为,矩阵乘法满足结合律,所以可以使用快速幂。
于是,用快速幂求出
(
1
1
1
0
)
n
−
2
\left( \begin{array}{c}1 & 1\\1 & 0\end{array}\right)^{n-2}
(1110)n−2 然后再乘上
(
f
(
2
)
f
(
1
)
)
\left( \begin{array}{c}f(2)\\f(1)\end{array}\right)
(f(2)f(1)) 即可。
代码:
#include <cstdio>
#include <cstring>
#define ll long long
#define mod 1000000007ll
struct matrix{
int w,h;
ll a[10][10];
matrix()
{
memset(a,0,sizeof(a));
}
matrix operator *(matrix x)
{
matrix re;re.h=h;re.w=x.w;
for(int i=1;i<=re.h;i++)
for(int j=1;j<=re.w;j++)
for(int k=1;k<=w;k++)
re.a[i][j]+=a[i][k]*x.a[k][j],re.a[i][j]%=mod;
return re;
}
};
ll n;
int main()
{
scanf("%lld",&n);
ll m=n-2;
matrix a,b;
a.w=1;a.h=2;
a.a[1][1]=1;
a.a[2][1]=1;
b.w=2;b.h=2;
b.a[1][1]=b.a[1][2]=b.a[2][1]=1;
matrix ans;ans.w=-1;
while(m>0)//快速幂
{
if(m%2==1)
{
if(ans.w==-1)ans=b;
else ans=ans*b;
}
b=b*b;
m/=2;
}
if(n<3)printf("1");
else printf("%lld\n",(ans*a).a[1][1]);
}