矩阵快速幂

矩阵快速幂

矩阵:

一个矩阵 \(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;
}

posted @ 2024-07-26 21:34  Atserckcn  阅读(4)  评论(0编辑  收藏  举报