Skip to content

矩阵快速幂

2021-10-28

简介

矩阵快速幂能将 O(n) 的线性递推优化成 O(logn)

矩阵

矩阵相当于二维数组。

  • 矩阵 Amn 列,称为 m×n 矩阵,简记为 Amn
  • 矩阵 Aij 列的元素写作 aij
A=[a11a12a1na21a22a2nam1am2amn]

单位矩阵

主对角线上的元素都为 1,其余元素为 0n×n 矩阵称为 n 阶单位矩阵,记作 InEn

In=[1000010000100001]

矩阵加减法

矩阵的加减法就是将两个矩阵对应位置上的元素相加减。

矩阵乘法

定义矩阵 A×B=C

  • 必须满足 A 的列数 = B 的行数;
  • Amr×Brn 会得到一个 m×n 矩阵 Cmn
  • C=A×B 的每个元素为cij=k=1raikbkj

任意矩阵乘 In 都等于它本身。

WARNING
  • 矩阵乘法满足结合律,不满足交换律;
  • 只有行数和列数相等的矩阵才能进行乘幂运算。

矩阵快速幂

基于 快速幂 的思想求 n 阶矩阵的 x 次方。时间复杂度:O(n3logx)

矩阵运算可能需要 高精度 或取模。

cpp
const int N = 101; // 矩阵的行数和列数

struct matrix {
    int at[N][N];
    matrix() { memset(at, 0, sizeof at); }
    int* operator[](int key) { return at[key]; }
};

matrix operator *(matrix a, matrix b) { // 矩阵 A × 矩阵 B
    matrix c;
    for (int i = 0; i < N; i ++)
        for (int j = 0; j < N; j ++)
            for (int k = 0; k < N; k ++)
                c[i][j] += a[i][k] * b[k][j];
    return c;
}

matrix operator ^(matrix a, int x) {    // 矩阵 A 的 x 次方
    matrix res;
    for (int i = 0; i < N; i ++)        // 初始化为单位矩阵
        res[i][i] = 1;
    while(x) {
        if(x % 2) res = res * a;
        a = a * a, x /= 2;
    }
    return res;
}

应用

若已知 f(1),f(2),且存在矩阵 A,使得对于任意 n 都有

A×[f(n)f(n1)]=[f(n+1)f(n)]

就可以推出 f(n) 的值。

(An2)×[f(2)f(1)]=[f(n)f(n1)]

可用矩阵快速幂求 An2。时间复杂度:O(logn)

例 1

求斐波那契数列的第 nf(n)n1012)。

f(n)={1n=1,2f(n1)+f(n2)n3

设矩阵 A=[a11a12a21a22] 满足

[a11a12a21a22]×[f(n)f(n1)]=[f(n+1)f(n)]

{f(n+1)=a11f(n)+a12f(n1)f(n)=a21f(n)+a22f(n1)

解得

{a11=1a12=1a21=1a22=0,A=[1110]

因此

[1110]n2×[f(2)f(1)]=[f(n)f(n1)]

f(1)=f(2)=1 代入即可。

cpp
int main() {
    matrix A;
    A[1][1] = 1, A[1][2] = 1;
    A[2][1] = 1, A[2][2] = 0;

    matrix B;
    B[1][1]	= 1;	// f(1) = 1
    B[2][1] = 1;	// f(2) = 1

    cin >> n;
    B = (A ^ (n - 2)) * B;
    cout << B[1][1];
}

例 2

求数列的第 nf(n)n1012)。

f(n)={1n=1,2f(n1)+f(n2)+n1n3

4 阶矩阵 A 满足

[a11a12a13a14a21a22a23a24a31a32a33a34a41a42a43a44]×[f(n)f(n1)n1]=[f(n+1)f(n)n+11]

解得

A=[1110100000110001]