P3390 矩阵快速幂
题目描述
给定n×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
取模
输入输出样例
In
2 1
1 1
1 1
Out
1 1
1 1
题解
思路
既然是快速幂, 那肯定和普通快速幂是一样的原理, 将指数分解, 然后用O(log k)
的复杂度计算最后的结果
矩阵乘法规则
定义n*p的矩阵和p*m的矩阵的乘法运算
[A*B=C
]
C为n*m的矩阵
矩阵每个元素的规则为:
[C_{i,j}=sum^{k=1}_{k<=p}{A_{i,k}*B_{k,j}}
]
一般快速幂
幂运算的基本性质
[a^{n+m}=a^{n}*a^{m}
]
得到特殊情况的推论
[a^{2n}=a^{n^{2}} \
a^{2n+1}=a^{n^{2}}*n
]
所以a的n次幂可以这样一直分解, 直到n=1或n=0的时候
由于矩阵乘法遵循结合率, 所以矩阵也可以这样求n次幂
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
struct Matrix {//矩阵结构体
long long a[105][105];
} mtx;
long long k, N;//k次幂, 矩阵大小N*N
Matrix operator*(Matrix x, Matrix y) {//重载矩阵乘法运算符
Matrix ans;
long long tmp;
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
for (int k = 1; k <= N; k++) {
tmp = x.a[k][j] * y.a[i][k];
tmp %= 1000000007;
ans.a[i][j] += tmp;
ans.a[i][j] %= 1000000007;
}
}
}
return ans;//返回一个矩阵
}
void print(Matrix x) {//输出矩阵x
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
printf("%lld ", x.a[i][j]);
}
printf("
");
}
return;
}
Matrix power(Matrix x, long long y) {//计算矩阵x的y次幂
Matrix ans;
if (y == 0) {//单位矩阵, 作为任何矩阵的0次幂
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (i == j) {
ans.a[i][j] = 1;
} else {
ans.a[i][j] = 0;
}
}
}
return ans;
}
if (y == 1) {//一次方是x本身
return x;
}
if (y == 2) {//二次方直接平方
return (x * x);
}
if (y % 2) { //奇次幂
ans = power(x, y >> 1);
return ans * ans * x;
} else {//偶次幂
ans = power(x, y >> 1);
return ans * ans;
}
return ans;
}
int main() {
scanf("%lld%lld", &N, &k);
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
scanf("%lld", &mtx.a[i][j]);
}
}//读入矩阵
print(power(mtx, k));
return 0;
}