概述
快速幂
当求某一正整数 a a a 的 n n n 次幂 a n a^n an 时,常用的做法是将 a a a 连续乘以 n n n 次,其时间复杂度为 O ( n ) O(n) O(n) 。 事实上,该问题有时间复杂度为 O ( l o g n ) O(logn) O(logn) 的解法。其核心思想是: a n = { a n / 2 ∗ a n / 2 , n 为偶数 a n / 2 ∗ a n / 2 ∗ a , i n 为奇数 a^n= begin{cases} a^{n/2},*,a^{n/2}, & text {$n$ 为偶数} \ a^{n/2},*,a^{n/2},*a, & text{i$n$ 为奇数} end{cases} an={an/2∗an/2,an/2∗an/2∗a,n 为偶数in 为奇数
代码如下:
/**
* 求 a 的 n 次幂
* @param a
* @param n
* @return
*/
long pow(int a, int n) {
long res = 1;
while(n != 0) {
if(n % 2 == 1) {
res *= a;
}
n /= 2;
a *= a;
}
return res;
}
矩阵快速幂
将上述的整数乘法改成矩阵乘法,就可快速幂推广至矩阵快速幂。
代码如下:
/**
* 矩阵 a 的 n 次幂
* @param a
* @param n
* @return
*/
int[][] pow(int[][] a, int n) {
int k = a.length;
int[][] res = new int[k][k];
for(int i = 0; i < k; i++) {
res[i][i] = 1;
}
while(n != 0) {
if(n % 2 == 1) {
res = mul(res, a);
}
n /= 2;
a = mul(a, a);
}
return res;
}
/**
* 矩阵乘法
* @param a
* @param b
* @return
*/
int[][] mul(int[][] a, int[][] b) {
int a_row = a.length;
int b_col = b[0].length;
int n = a[0].length; //a的列数等于b的行数
int[][] res = new int[a_row][b_col];
for(int i = 0; i < a_row; i++) {
for(int j = 0; j < b_col; j++) {
for(int k = 0; k < n; k++) {
res[i][j] += a[i][k] * b[k][j];
}
}
}
return res;
}
线性dp优化
一组 D P DP DP 状态,其实等价于一个向量。而DP状态的转移方程,可以是对一个向量做变形的矩阵。那么本质上从一个向量到另一个状态的向量,是可以通过一个矩阵来做到。矩阵具有结合律,我们可以先对右半部分矩阵用快速幂得到一个终极的变形矩阵,再乘以向量,就可以把 O ( n ) O(n) O(n) 的计算优化到 O ( l o g ( n ) ) O (log (n)) O(log(n))。 (转自简书——DP的五类优化-快速幂,四边形不等式)
例题:
1、 F i b o n a c c i Fibonacci Fibonacci 数列
递推式: F n = F n − 1 + F n − 2 , ( n > 2 ) F_n=F_{n-1}+F_{n-2},;(n > 2) Fn=Fn−1+Fn−2,(n>2)
d p dp dp 状态转移方程: d p [ n ] = d p [ n − 1 ] + d p [ n − 2 ] , ( n > 2 ) dp[n] = dp[n-1] +dp[n-2],;(n>2) dp[n]=dp[n−1]+dp[n−2],(n>2)
由
F
i
b
o
n
a
c
c
i
Fibonacci
Fibonacci 数列的递推式可以得到如下矩阵关系式:
(
F
n
F
n
−
1
)
=
(
1
1
1
0
)
(
F
n
−
1
F
n
−
2
)
=
(
1
1
1
0
)
n
−
2
(
F
2
F
1
)
begin{pmatrix} F_n \ F_{n-1} end{pmatrix} = begin{pmatrix} 1 & 1 \ 1 & 0 end{pmatrix} begin{pmatrix} F_{n-1} \ F_{n-2} end{pmatrix} = begin{pmatrix} 1 & 1 \ 1 & 0 end{pmatrix}^{n-2} begin{pmatrix} F_2 \ F_1 end{pmatrix}
(FnFn−1)=(1110)(Fn−1Fn−2)=(1110)n−2(F2F1)
故该问题转换成矩阵的
n
n
n 次幂,实现代码如下:
/**
* 求f(n)
* @param n
* @return
*/
int fibonacci(int n) {
if(n == 0) {
return 0;
}
if(n <= 2) {
return 1;
}
int[][] initial = {{1}, {1}}; //f(2), f(1)
int[][] transition = {{1, 1}, {1, 0}}; //转换矩阵
int[][] result = new int[2][2]; //结果矩阵 f(n), f(n-1)
result = mul(pow(transition, n - 2), initial);
return result[0][0];
}
注: m u l mul mul 函数和 p o w pow pow 函数均为矩阵快速幂部分中的对应函数
现在有一个问题——如何得到转换矩阵?
未想到通解。。。
2、CCF202006第四题 1246 ( d i g i t s ) 1246(digits) 1246(digits)
后续更新。。。
最后
以上就是慈祥高跟鞋为你收集整理的快速幂-矩阵快速幂-线性dp优化的全部内容,希望文章能够帮你解决快速幂-矩阵快速幂-线性dp优化所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复