【洛谷P3390】(模板)矩阵快速幂

题目链接

(模板)矩阵快速幂

题目背景

矩阵快速幂

题目描述

给定\(n\times n\)的矩阵\(A\),求\(A^k\)

输入格式

第一行两个整数\(n,k\)接下来\(n\)行,每行\(n\)个整数,第\(i\)行的第\(j\)的数表示\(A_{i,j}\)

输出格式

输出\(A^k\)\(n\)行,每行\(n\)个数,第\(i\)行第\(j\)个数表示\((A^k)_{i,j}\),每个元素对\(10^9+7\)取模。

样例输入

2 1
1 1
1 1

样例输出

1 1
1 1

说明/提示

【数据范围】
对于\(100\%\)的数据:\(1\le n \le 100\)\(0 \le k \le 10^{12}\),\(|A_{i,j}| \le 1000\)

题解

明显这是一道矩阵快速幂的板题,下面先介绍一下矩阵快速幂吧。
矩阵快速幂就是把矩阵乘法和快速幂结合一下。
对于矩阵的计算,这里就讲一下矩阵乘法,其他运算就不赘述了。
对于两个矩阵\(A\)\(B\),它们的行数和列数分别为\(ax,ay,bx,by\)
要能进行\(A \times B\),需要满足\(ay=bx\)
\(A \times B\)的结果是矩阵\(C\)\(C\)的行数和列数分别为\(ax,by\)\(C_{j,i}=\sum^{ay}_{k=1}A_{j,k}*B_{k,i}\)
也就是说\(C\)的第\(i\)行第\(j\)列等于\(A\)的第\(i\)行和\(B\)的第\(j\)列,各个对应的数的乘积的和。
关于快速幂的话想必大家都会了,那么我们只要定义一个\(struct\)来存储矩阵,然后重载一下运算符,就和普通的快速幂没有区别了。
如果不会重载运算符的话也可以写一个函数。
注意:因为中间有乘法,所以要开\(long\ long\),还要记得取模,刚开始打的时候取模少了一个\(0\),调了半天o(╥﹏╥)o
上代码:

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
int n;
long long k;
struct aa{
	long long a[109][109];
	aa operator * (aa x){
		aa uans;
		for(int j=1;j<=n;j++)
			for(int i=1;i<=n;i++){
				uans.a[j][i]=0;
				for(int p=1;p<=n;p++)
					uans.a[j][i]=(uans.a[j][i]+a[j][p]*x.a[p][i]%mod)%mod;
			}
		return uans;
	}
};
aa ksm(aa x,long long p){
	aa uans;
	for(int j=1;j<=n;j++)
		for(int i=1;i<=n;i++)
			if(i==j) uans.a[j][i]=1;
			else uans.a[j][i]=0;
	while(p){
		if(p&1) uans=uans*x;
		x=x*x;
		p>>=1;
	}
	return uans;
}
int main(){
	scanf("%d%lld",&n,&k);
	aa a;
	for(int j=1;j<=n;j++)
		for(int i=1;i<=n;i++)
			scanf("%lld",&a.a[j][i]);
	aa ans=ksm(a,k);
	for(int j=1;j<=n;j++){
		for(int i=1;i<=n;i++)
			printf("%lld ",ans.a[j][i]);
		puts("");
	}
	return 0;
}
posted @ 2020-06-08 20:51  oblivionl  阅读(151)  评论(0编辑  收藏  举报