矩阵快速幂
矩阵:
一个矩阵
A
A
A,是由
n
×
m
n\times m
n×m 个数字组成,
B
B
B 由
m
×
p
m\times p
m×p 组成,详见下。
A
=
[
a
1
,
1
,
a
1
,
2
,
a
1
,
3
⋯
a
1
,
m
a
2
,
1
,
a
2
,
2
,
a
2
,
3
⋯
a
2
,
m
⋅
⋅
⋅
a
n
,
1
,
a
n
,
2
,
a
n
,
3
⋯
a
n
,
m
]
B
=
[
b
1
,
1
,
b
1
,
2
,
b
1
,
3
⋯
b
1
,
p
b
2
,
1
,
b
2
,
2
,
b
2
,
3
⋯
b
2
,
p
⋅
⋅
⋅
b
m
,
1
,
b
m
,
2
,
b
m
,
3
⋯
b
m
,
p
]
A=\begin{bmatrix}a_{1,1},a_{1,2},a_{1,3}\cdots a_{1,m} \\ a_{2,1},a_{2,2},a_{2,3}\cdots a_{2,m} \\ \cdot \\ \cdot \\ \cdot \\ a_{n,1},a_{n,2},a_{n,3}\cdots a_{n,m}\end{bmatrix} \\ \\ B=\begin{bmatrix}b_{1,1},b_{1,2},b_{1,3}\cdots b_{1,p} \\ b_{2,1},b_{2,2},b_{2,3}\cdots b_{2,p} \\ \cdot \\ \cdot \\ \cdot \\ b_{m,1},b_{m,2},b_{m,3}\cdots b_{m,p} \end{bmatrix}
A=
a1,1,a1,2,a1,3⋯a1,ma2,1,a2,2,a2,3⋯a2,m⋅⋅⋅an,1,an,2,an,3⋯an,m
B=
b1,1,b1,2,b1,3⋯b1,pb2,1,b2,2,b2,3⋯b2,p⋅⋅⋅bm,1,bm,2,bm,3⋯bm,p
注意到,
A
A
A 的列数与
B
B
B 的行数均为
m
m
m,将其定义为可以进行矩阵乘法的两个矩阵。
如何相乘?
若其乘积为矩阵
C
C
C,则
C
C
C 为一个
n
×
p
n\times p
n×p 的矩阵,乘积过程为:
c
i
,
j
=
∑
k
=
1
m
a
i
,
k
×
b
k
,
j
c_{i,j}=\sum_{k=1}^{m} a_{i,k}\times b_{k,j}
ci,j=k=1∑mai,k×bk,j
代码:
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
c[i][j]+=a[i][k]*b[k][j];
这不就是Floyd吗。。
将
A
A
A 描述成
n
n
n 个行向量的集合,
B
B
B 表示为
p
p
p 个列向量的集合,如下。
A
=
[
a
1
a
2
a
3
⋅
⋅
⋅
a
n
]
B
=
[
b
1
,
b
2
,
b
3
⋯
b
p
]
A=\begin{bmatrix} a_1 \\ a_2 \\ a_3 \\ \cdot \\ \cdot \\ \cdot \\ a_n \end{bmatrix} \\ \\ \\ B=\begin{bmatrix} b_1,b_2,b_3 \cdots b_p \end{bmatrix}
A=
a1a2a3⋅⋅⋅an
B=[b1,b2,b3⋯bp]
则
C
C
C 为:
C
=
[
a
1
×
b
1
,
a
1
×
b
2
,
a
1
×
b
3
⋯
a
1
×
b
p
a
2
×
b
1
,
a
2
×
b
2
,
a
2
×
b
3
,
⋯
a
2
×
b
p
⋅
⋅
⋅
a
n
×
b
1
,
a
n
×
b
2
,
a
n
×
b
3
⋯
a
n
×
b
p
]
C=\begin{bmatrix}a_1\times b_1\ ,\ a_1\times b_2\ ,\ a_1\times b_3\cdots a_1\times b_p \\ a_2\times b_1\ ,\ a_2\times b_2\ ,\ a_2\times b_3\ ,\cdots a_2\times b_p \\ \cdot \\ \cdot \\ \cdot \\ a_n\times b_1\ ,\ a_n\times b_2\ ,\ a_n\times b_3\cdots a_n\times b_p \end{bmatrix}
C=
a1×b1 , a1×b2 , a1×b3⋯a1×bpa2×b1 , a2×b2 , a2×b3 ,⋯a2×bp⋅⋅⋅an×b1 , an×b2 , an×b3⋯an×bp
上文提到,若 A A A 与 B B B 有一个 m m m 相等,则它们有一个单位元,可以使其相乘后不影响结果。
更清楚的具体方法如下,可以更好地解释上句话。
- 以 A A A 的每个成员去匹配 B B B 的每个成员
例题:P3390 【模板】矩阵快速幂
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7,MAXN=105;
ll n,m;
ll ans[MAXN][MAXN],a[MAXN][MAXN],t[MAXN][MAXN];
inline void mul1()
{
memset(t,0,sizeof(t));
for(ll k=1;k<=n;k++)
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
t[i][j]=(t[i][j]+ans[i][k]*a[k][j])%mod;
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
ans[i][j]=t[i][j];
return;
}
inline void mul2()
{
memset(t,0,sizeof(t));
for(ll k=1;k<=n;k++)
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
t[i][j]=(t[i][j]+a[i][k]*a[k][j])%mod;
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
a[i][j]=t[i][j];
return;
}
inline void quickpow()
{
while(m)
{
if(m&1)
mul1();
mul2();//千万不能加else!!!(血泪教训)
m>>=1;
}
return;
}
int main(){
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++)
for(ll j=1;j<=n;j++)
scanf("%lld",&a[i][j]);
for(ll i=1;i<=n;i++)
ans[i][i]=1;
quickpow();
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=n;j++)
printf("%lld ",ans[i][j]%mod);
putchar('\n');
}
return 0;
}