矩阵快速幂笔记

文章目录

  • 矩阵快速幂
    • 常规求幂
    • 递归
    • 快速幂
    • 矩阵快速幂
      • 矩阵乘法求解递归状态转移
      • 确定矩阵A
      • java 代码实现
  • 参考资料

矩阵快速幂

常规求幂

a n a^n an的值,如果用纯for循环,要循环n次乘a。
时间复杂度:O(n)
空间复杂度:S(1)

递归

与二分法异曲同工。
例:
a 57 = { a 28 { a 14 { a 7 { a 3 { a a a a 3 a a 7 a 14 a 28 a a^{57} = \left \{\begin{matrix} a^{28} & \left \{\begin{matrix} a^{14} & \left \{\begin{matrix} a^{7} & \left \{\begin{matrix} a^{3} & \left \{\begin{matrix} a \\ a \\ a \end{matrix} \right.\\ a^{3} \\ a \end{matrix} \right.\\ a^{7} \\ \end{matrix} \right.\\ a^{14} \\ \end{matrix} \right.\\ a^{28}\\ a \end{matrix} \right. a57=a28a28aa14a14a7a7a3a3aaaa
只需要将幂次二分,取平方(再乘a)即可。
a 2 k = { a k a k a 2 k + 1 = { a k a k a a^{2k}= \begin{cases} a^k\\ a^k\\ \end{cases}\\ a^{2k+1}= \begin{cases} a^k\\ a^k\\ a \end{cases} a2k={akaka2k+1=akaka
时间复杂度:O(logn)
空间复杂度:O(logn)

快速幂

对n进行二进制分解。
例:求解 a 57 a^{57} a57

  1. 将57转为二进制111001,对二进制为1的位取值,即
    a 57 = a 1 ∗ a 8 ∗ a 16 ∗ a 32 a^{57} = a^{1} * a^{8} * a^{16} * a^{32} a57=a1a8a16a32
  2. 求每位二进制的值:
    1. 初始化a = 1
    2. 从低位起,每位二进制值为a *= a
  3. 将二进制为1的位取值相乘。
public int MOD = 1000000007;

public static int qp(int a, int n) {
    int ans = 1;
    while (n > 0) {
        if ((n&1) == 1) {
            ans = (int) (((long)ans * a) % MOD);
        }
        a = (int) (((long)a * a) % MOD);
        n >>= 1;
    }
    return ans;
}

矩阵快速幂

矩阵乘法求解递归状态转移

以求解斐波那契数列为例

f ( n ) = { f ( n − 1 ) + f ( n − 2 ) n > 1 1 0 < = n < = 1 f(n) = \begin{cases} f(n-1) + f(n-2) & n > 1 \\ 1 & 0<=n<=1 \end{cases} f(n)={f(n1)+f(n2)1n>10<=n<=1

利用矩阵乘法
[ 0 1 1 1 ] [ f ( n − 2 ) f ( n − 1 ) ] = [ f ( n − 1 ) f ( n ) ] \begin{bmatrix} 0&1\\ 1&1 \end{bmatrix} \begin{bmatrix} f(n-2)\\ f(n-1) \end{bmatrix}= \begin{bmatrix} f(n-1)\\ f(n) \end{bmatrix} [0111][f(n2)f(n1)]=[f(n1)f(n)]

设定矩阵为A
A = [ 0 1 1 1 ] A = \begin{bmatrix} 0&1\\ 1&1 \end{bmatrix} A=[0111]
则可以分解最终矩阵为
[ f ( n ) f ( n + 1 ) ] = A n [ f ( 0 ) f ( 1 ) ] \begin{bmatrix} f(n)\\ f(n+1) \end{bmatrix}= A^{n} \begin{bmatrix} f(0)\\ f(1) \end{bmatrix} [f(n)f(n+1)]=An[f(0)f(1)]

确定矩阵A

任意状态转移方程均可确定矩阵A,例:
f ( n ) = 3 f ( n − 1 ) + 6 f ( n − 2 ) − 7 f ( n − 3 ) [ 0 1 0 0 0 1 − 7 6 3 ] [ f ( 0 ) f ( 1 ) f ( 2 ) ] = [ f ( 1 ) f ( 2 ) f ( 3 ) ] A = [ 0 1 0 0 0 1 − 7 6 3 ] f(n) = 3f(n-1) + 6f(n-2) - 7f(n-3) \\ \begin{bmatrix} 0&1&0\\ 0&0&1\\ -7&6&3 \end{bmatrix} \begin{bmatrix} f(0)\\ f(1)\\ f(2) \end{bmatrix}= \begin{bmatrix} f(1)\\ f(2)\\ f(3) \end{bmatrix} \\ A = \begin{bmatrix} 0&1&0\\ 0&0&1\\ -7&6&3 \end{bmatrix} f(n)=3f(n1)+6f(n2)7f(n3)007106013f(0)f(1)f(2)=f(1)f(2)f(3)A=007106013

java 代码实现

public static int[][] matrix_qp(int n) {
    //以斐波那契数列为例
    //矩阵A
    //0 1
    //1 1
    int[][] A = new int[2][2];
    A[0][0] = 0;
    A[0][1] = A[1][0] = A[1][1] = 1;

    //斐波那契数列0 1矩阵
    //1 0
    //1 0
    int[][] F = new int[2][2];
    F[0][0] = F[1][0] = 1;
    F[0][1] = F[1][1] = 0;

    return matrix_multi(matrix_mi(A, n), F);
}

public static int[][] matrix_multi(int[][] a, int[][] b) {
    int[][] ans = new int[2][2];
    for (int i = 0; i < 2; ++i)
        for (int j = 0; j < 2; ++j)
            for (int k = 0; k < 2; ++k)
                ans[i][j] += a[i][k] * b[k][j];
    return ans;
}

public static int[][] matrix_mi(int[][] a, int n) {
    int[][] ans = new int[2][2];
    ans[0][0] = ans[1][1] = 1;
    while(n > 0) {
        if ((n&1) == 1)
            ans = matrix_multi(ans, a);
        a = matrix_multi(a, a);
        n >>= 1;
    }
    return ans;
}

public static void show_matrix(int[][] a) {
    System.out.println("Matrix");
    for (int i = 0; i < a.length; ++i) {
        for (int j = 0; j < a[i].length; ++j)
            System.out.print(a[i][j] + " ");
        System.out.println();
    }
}

上述代码未作模运算。

做模运算时需注意:

当矩阵包含负数时,要保证被模数大与0

(a%c - b%c + c)%c

参考资料

矩阵快速幂 - b站

你可能感兴趣的:(算法)