P3390 【模板】矩阵快速幂
题目传送门
一、复习整数快速幂
https://www.jianshu.com/p/749b6ee1d001
#include
using namespace std;
//栗子: 2^11 = 2 ^ (1011)2
//就是把11拆成二进制数位,然后从右到左进行次方base的迭乘
//在从右到左的枚举过程中,发现本位是1,就乘上本位的base
//原来需要2*2*...*2,共10次,即O(N)
//现在需要log以2为底11就是log_2{11} 即4次
int qmi(int a, int b) {
int ans = 1;
while (b) {
if (b & 1) ans *= a;
a *= a; //次方base
b >>= 1;
}
return ans;
}
int main() {
cout << qmi(2, 11) << endl;
return 0;
}
二、单位矩阵
在普通的乘法中,一个数乘\(1\)还是等于它本身,在矩阵乘法中也有这么一个“\(1\)”,它就是单位矩阵
不同于普通乘法中的单位\(1\),对于不同矩阵他们的单位矩阵大小是不同的
对于\(n*m\)的矩阵,它的单位矩阵大小为\(m*m\),对于\(m*n\)的矩阵,它的单位矩阵大小为\(n*n\)
也就是说单位矩阵都是正方形的,这是因为只有正方形的矩阵能保证结果和前一个矩阵形状相同
单位矩阵的元素非\(0\)即\(1\),从左上角到右下角的对角线上元素皆为\(1\),其他皆为\(0\)
三、模板解法I
#include
using namespace std;
//矩阵快速幂
typedef long long LL;
const int MOD = 1e9 + 7;
const int N = 110;
LL n, k; //本题数据范围很大,用int直接wa哭了
//矩阵声明
struct JZ {
LL m[N][N];
} A, res, base;
//矩阵乘法
inline JZ mul(JZ A, JZ B) {
JZ C;
memset(C.m, 0, sizeof(C.m));
for (LL i = 0; i < n; i++)
for (LL j = 0; j < n; j++)
for (LL k = 0; k < n; k++) {
C.m[i][j] += (A.m[i][k] % MOD) * (B.m[k][j] % MOD);
C.m[i][j] %= MOD;
}
return C;
}
void qmi() {
//将结果矩阵初始化为单位矩阵
memset(res.m, 0, sizeof res.m);
for (int i = 0; i < n; i++) res.m[i][i] = 1;
//其实就是把整数快速幂修改为矩阵快速幂
while (k) { //二进制快速幂
if (k & 1) res = mul(res, A); // 联想一下整数快速幂
A = mul(A, A); // base 翻倍
k >>= 1;
}
}
int main() {
cin >> n >> k;
//输入原始矩阵
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> A.m[i][j];
//计算矩阵快速幂
qmi();
//输出
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
cout << res.m[i][j] << " ";
cout << endl;
}
return 0;
}
四、模板解法II
#include
using namespace std;
//矩阵快速幂
typedef long long LL;
const int MOD = 1e9 + 7;
const int N = 110;
LL n, k; //本题数据范围很大,用int直接wa哭了
LL C[N][N], A[N][N], B[N][N];
//矩阵乘法
void mul(LL C[][N], LL A[][N], LL B[][N]) {
//为什么非得要开一个临时的tmp来存结果呢,直接用C确实不行,原理不清楚
static LL tmp[N][N];
memset(tmp, 0, sizeof tmp);
for (LL i = 0; i < n; i++)
for (LL j = 0; j < n; j++)
for (LL k = 0; k < n; k++) {
tmp[i][j] += A[i][k] * B[k][j] % MOD; //矩阵乘法
tmp[i][j] %= MOD;
}
memcpy(C, tmp, sizeof tmp);
}
void qmi() {
//将结果矩阵初始化为单位矩阵
memset(B, 0, sizeof B);
for (int i = 0; i < n; i++) B[i][i] = 1;
//其实就是把整数快速幂修改为矩阵快速幂
while (k) { //二进制快速幂
if (k & 1) mul(B, B, A); // 联想一下整数快速幂
mul(A, A, A); // base 翻倍
k >>= 1;
}
}
int main() {
cin >> n >> k;
//输入原始矩阵
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> A[i][j];
//计算矩阵快速幂
qmi();
//输出
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
cout << B[i][j] << " ";
cout << endl;
}
return 0;
}