矩阵快速幂
常规求幂
求
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=⎩⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎧a28a28a⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧a14a14⎩⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎧a7a7⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧a3a3a⎩⎨⎧aaa
只需要将幂次二分,取平方(再乘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
- 将57转为二进制
111001
,对二进制为1的位取值,即
a 57 = a 1 ∗ a 8 ∗ a 16 ∗ a 32 a^{57} = a^{1} * a^{8} * a^{16} * a^{32} a57=a1∗a8∗a16∗a32 - 求每位二进制的值:
- 初始化
a = 1
- 从低位起,每位二进制值为
a *= a
- 初始化
- 将二进制为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(n−1)+f(n−2)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(n−2)f(n−1)]=[f(n−1)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(n−1)+6f(n−2)−7f(n−3)⎣⎡00−7106013⎦⎤⎣⎡f(0)f(1)f(2)⎦⎤=⎣⎡f(1)f(2)f(3)⎦⎤A=⎣⎡00−7106013⎦⎤
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