我是靠谱客的博主 慈祥高跟鞋,这篇文章主要介绍快速幂-矩阵快速幂-线性dp优化,现在分享给大家,希望可以做个参考。

快速幂

当求某一正整数 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/2an/2,an/2an/2a,n 为偶数in 为奇数

代码如下

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/** * 求 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; }

矩阵快速幂

将上述的整数乘法改成矩阵乘法,就可快速幂推广至矩阵快速幂。

代码如下

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/** * 矩阵 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=Fn1+Fn2,(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[n1]+dp[n2],(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} (FnFn1)=(1110)(Fn1Fn2)=(1110)n2(F2F1)
故该问题转换成矩阵的 n n n 次幂,实现代码如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/** * 求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优化内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(70)

评论列表共有 0 条评论

立即
投稿
返回
顶部