矩阵快速幂
矩阵快速幂
矩阵:
一个矩阵 \(A\),是由 \(n\times m\) 个数字组成,\(B\) 由 \(m\times 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\) 的列数与 \(B\) 的行数均为 \(m\),将其定义为可以进行矩阵乘法的两个矩阵。
如何相乘?
若其乘积为矩阵 \(C\),则 \(C\) 为一个 \(n\times p\) 的矩阵,乘积过程为:
\[c_{i,j}=\sum_{k=1}^{m} a_{i,k}\times b_{k,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\) 描述成 \(n\) 个行向量的集合,\(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}
\]
则 \(C\) 为:
\[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}
\]
上文提到,若 \(A\) 与 \(B\) 有一个 \(m\) 相等,则它们有一个单位元,可以使其相乘后不影响结果。
更清楚的具体方法如下,可以更好地解释上句话。
- 以 \(A\) 的每个成员去匹配 \(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;
}