矩阵快速幂
矩阵:
一个矩阵 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;
}