题目地址:P1962 斐波那契数列 - 洛谷 | 计算机科学教育新生态 ↗
前置知识点
矩阵
定义:
一个n×m矩阵是由n×m个实数排列成n行m列构成的,用一对[]括起来。
下面3×3矩阵简记为A=(aij)3×3
A=a11a21a31a12a22a32a13a23a33
矩阵加减
n行m列矩阵A,B加减规则:A±B=(aij±bij)n×m
矩阵加减满足交换律,结合律
A±B=a11a21⋯an1a12a22⋯an2⋯⋯⋯⋯a1ma2m⋯anm±b11b21⋯bn1b12b22⋯bn2⋯⋯⋯⋯b1mb2m⋯bnm=a11±b11a21±b21⋯an1±bn1a12±b12a22±b22⋯an2±bn2⋯⋯⋯⋯a1m±b1ma2m±b2m⋯anm±bnm
矩阵乘法
**1.数和矩阵相乘
kA=Ak=ka11ka21⋯kan1ka12ka22⋯kan2⋯⋯⋯⋯ka1mka2m⋯kanm
2.矩阵和矩阵相乘
原理:Cij=A的第i行和B的第j列每个元素对应相乘的和。
所以矩阵乘法当且仅当A的列数=B的行数时才有定义。
由于矩阵乘法的规则,A⋅B=B⋅A
具体方法:Cij=ai1b1j+ai2b2j+⋯+aitbtj=∑r=1tairbrj
实现
struct matrix {
int n, m;
int a[100][100];
};
// A.m == B.n
matrix matrix_mul(matrix A, matrix B) {
matrix C;
C.n = A.n;
C.m = B.m;
for (int i = 0; i < A.n; ++i) {
for (int j = 0; j < B.m; ++j) {
C.a[i][j] = 0;
for (int k = 0; k < A.m; ++k) {
C.a[i][j] += A.a[i][k] * B.a[k][j];
}
}
}
return C;
}
cpp
单位矩阵
形如:
10⋯001⋯0⋯⋯⋯000⋯1
主对角线上元素均为1,其余元素均为0的矩阵。通常记做In或En
性质:
A⋅In=A
In⋅A=A
即任何一个矩阵左乘或右乘单位矩阵,结果不变(相当于乘法当中的 1 )
矩阵快速幂
快速幂
int quick_power(int x,int y){
int ans = 1,cnt = x;
while(y){
if(y & 1){
ans *= cnt;
}
cnt *= cnt;
y >>= 1;
}
return ans;
}
cpp
矩阵快速幂
利用快速幂思想,快速求矩阵An
将快速幂中的乘法替换为矩阵乘法,参数和返回值替换为矩阵即可。
int n; // 所有矩阵都是 n * n 的矩阵
struct matrix {
int a[100][100];
};
matrix matrix_mul(matrix A, matrix B, int mod) {
// 2 个矩阵相乘
matrix C;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
C.a[i][j] = 0;
for (int k = 0; k < n; ++k) {
C.a[i][j] = (C.a[i][j] + A.a[i][k] * B.a[k][j] % mod) % mod;
}
}
}
return C;
}
matrix unit() {
// 返回一个单位矩阵
matrix res;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (i == j) {
res.a[i][j] = 1;
} else {
res.a[i][j] = 0;
}
}
}
return res;
}
matrix matrix_pow(matrix A, int p, int mod) {
// 快速求矩阵 A 的 p 次方
matrix res = unit();
while (p > 0) {
if (p & 1) {
res = matrix_mul(res, A, mod);
}
A = matrix_mul(A, A, mod);
p >>= 1;
}
return res;
}
cpp
本题题解
斐波那契数列递推式:
an=an−1+an−2
设Ai=[ai,ai+1]
先构造1×2的矩阵A1=[a1,a2],考虑构造矩阵 B 使得 A1×B=A2
通过观察推导得到B=[0111]
∴A2=A1×B∴A3=A2×B=A1×B×B=A1×B2
⋯
Ai=A1×Bi−1=[1,1]×[0111]i−1
时间复杂度:O(logN)
Preview: