矩阵快速幂
- 矩阵快速幂适用于线性递推数列
- 矩阵乘法不满足交换律
- 利用二进制分解和矩阵乘法的结合性质,来大幅减少计算量
-
在计算过程中,从高位到低位依次处理二进制位:
- 初始化结果矩阵为单位矩阵。
- 若当前位为 1,则将当前结果矩阵乘以原矩阵。
- 每次循环将原矩阵平方。
运行代码
typedef long long ll;
const int mod = 1e9 + 7;
struct matrix {
ll c[3][3];
matrix() {
memset(c, 0, sizeof c);
}
}A, F;
ll n, k;
matrix operator*(matrix& x, matrix& y) {
matrix t;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
t.c[i][j] = (t.c[i][j] + x.c[i][k] * y.c[k][j]) % mod;
return t;
}
void quick_pow(ll k) {//快速幂
for (int i = 1; i <= n; i++)
F.c[i][i] = 1;
while (k) {
if (k & 1)F = F * A;
A = A * A;
k >>= 1;
}
}
代码思路
数据类型和常量定义:
typedef long long ll
:定义了一个长整型别名ll
,方便后续使用。const int mod = 1e9 + 7
:定义了一个常量mod
,用于后续的取模运算。
结构体定义:
- 定义了一个名为
matrix
的结构体来表示矩阵。- 内部使用二维数组
ll c[3][3]
存储矩阵元素。 - 构造函数将矩阵元素初始化为 0。
- 内部使用二维数组
运算符重载:重载了 *
运算符,用于实现两个矩阵的乘法运算,并对结果取模 mod
。
快速幂函数 quick_pow
:
- 初始化矩阵
F
为单位矩阵。 - 通过一个循环,根据
k
的二进制位进行计算。- 当当前二进制位为 1 时,将
F
乘以A
,并更新F
。 - 每次循环将
A
自乘(平方)。 - 通过不断右移
k
,逐位处理,最终实现快速计算矩阵的k
次幂。
- 当当前二进制位为 1 时,将
P1962 斐波那契数列
题目描述
P1962 斐波那契数列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
运行代码
#include<iostream>
using namespace std;
#include<algorithm>
#include<string.h>
typedef long long ll;
const int N = 1e9 + 7;
struct matrix {
ll c[3][3];
matrix() {
memset(c, 0, sizeof c);
}
}F, A;//F为斐波那契矩阵,A为构造矩阵
ll n;
matrix operator*(matrix& x, matrix& y) {//矩阵乘法
matrix t;//临时矩阵
for (int i = 1; i <= 2; i++)
for (int j = 1; j <= 2; j++)
for (int k = 1; k <= 2; k++)
t.c[i][j] = (t.c[i][j] + x.c[i][k] * y.c[k][j]) % N;
return t;
}
void quick_pow(ll n) {
F.c[1][1] = F.c[1][2] = 1;
A.c[1][1] = A.c[1][2] = A.c[2][1] = 1;
while (n) {
if (n & 1) F = F * A;
A = A * A;
n >>= 1;
}
}
int main() {
scanf_s("%lld", &n);
if (n <= 2) {
puts("1"); return 0;
}
quick_pow(n - 2);
cout << F.c[1][1];
return 0;
}
代码思路
调用快速矩阵幂的模板
主函数 main
:
- 读取输入的整数
n
。 - 对于
n <= 2
的情况,直接输出 1 并结束程序。 - 对于
n > 2
的情况,调用quick_pow(n - 2)
进行计算。 - 最后输出
F
矩阵的特定元素F.c[1][1]
。
例如,如果输入 n = 5
:
- 首先在
quick_pow
函数中,初始化F
和A
矩阵。 - 3 的二进制为 11,第一次循环,最低位为 1,所以
F = F * A
。 - 然后
A = A * A
。 - 第二次循环,最高位为 1,
F = F * A
,得到最终的F
矩阵。
P1939 矩阵加速(数列)
题目描述
P1939 矩阵加速(数列) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
运行代码
#include<iostream>
using namespace std;
#include<algorithm>
#include<string.h>
typedef long long ll;
const int N = 1e9 + 7;
struct matrix {
ll c[4][4];
matrix() {
memset(c, 0, sizeof c);
}
}F, A;//F为斐波那契矩阵,A为构造矩阵
ll n,T;
matrix operator*(matrix& x, matrix& y) {//矩阵乘法
matrix t;//临时矩阵
for (int i = 1; i <= 3; i++)
for (int j = 1; j <= 3; j++)
for (int k = 1; k <= 3; k++){
t.c[i][j] += x.c[i][k] * y.c[k][j] % N;
t.c[i][j] %= N;
}
return t;
}
void quick_pow(ll n) {
F.c[1][1] = F.c[1][2] = F.c[1][3] = 1;
memset(A.c, 0, sizeof(A.c));
A.c[1][1] = A.c[1][2] = A.c[2][3] = A.c[3][1] = 1;
while (n) {
if (n & 1) F = F * A;
A = A * A;
n >>= 1;
}
}
int main() {
scanf_s("%lld", &T);
while (T--) {
scanf_s("%lld", &n);
if (n <= 3) {
puts("1");
continue;
}
quick_pow(n -3);
cout << F.c[1][1]<<endl;
}
return 0;
}
代码思路
调用快速矩阵幂的模板
主函数 main
:
- 读取测试用例的数量
T
。 - 在一个循环中处理每个测试用例:
- 读取当前测试用例的输入
n
。 - 对于
n <= 3
的情况,直接输出 1 并继续下一个测试用例。 - 对于
n > 3
的情况,调用quick_pow(n - 3)
进行计算,然后输出F
矩阵的特定元素。
- 读取当前测试用例的输入
例如,如果输入 T = 2
,第一个测试用例 n = 5
,第二个测试用例 n = 7
:
- 对于第一个测试用例,初始化
F
和A
矩阵,计算n - 3 = 2
的快速幂,得到更新后的F
矩阵,并输出其特定元素。 - 对于第二个测试用例,同样的流程进行处理。