矩阵快速幂基于快速幂原理,也就是二进制倍增的原理。可以用来求递增式的解。
首先我们来说一个简单的递增式:
f(n)=f(n−1)+f(n−2),f(0)=1,f(1)=1
f
(
n
)
=
f
(
n
−
1
)
+
f
(
n
−
2
)
,
f
(
0
)
=
1
,
f
(
1
)
=
1
1.第一步要做的是构造矩阵:
[f(n)f(n−1)]=[1110]×[f(n)f(n−1)]=[1110]2×[f(n)f(n−1)]=...=[1110]n−1×[f(1)f(0)]
[
f
(
n
)
f
(
n
−
1
)
]
=
[
1
1
1
0
]
×
[
f
(
n
)
f
(
n
−
1
)
]
=
[
1
1
1
0
]
2
×
[
f
(
n
)
f
(
n
−
1
)
]
=
.
.
.
=
[
1
1
1
0
]
n
−
1
×
[
f
(
1
)
f
(
0
)
]
2.从上面矩阵我们可以看出,只要求出知道前两项,就可以通过矩阵运算求出第n项。如果不用快速幂,直接计算矩阵的话,那每次矩阵运算复杂度为8,也就是复杂度为
O((n−2)∗8+4)=O(n)
O
(
(
n
−
2
)
∗
8
+
4
)
=
O
(
n
)
。如果使用矩阵快速幂,那么复杂度就是
O(log2(n−1)+4)=O(log2n)
O
(
l
o
g
2
(
n
−
1
)
+
4
)
=
O
(
l
o
g
2
n
)
。
#include <bits/stdc++.h>
using namespace std;
struct Mat {
int c[2][2];
Mat() {
memset(c, 0, sizeof(c));
}
Mat operator * (const Mat& o) {
Mat ans;
for(int i = 0; i < 2; ++ i) {
for(int j = 0; j < 2; ++ j) {
for(int k = 0; k < 2; ++ k) {
ans.c[i][j] += c[i][k] * o.c[k][j];
}
}
}
return ans;
}
};
Mat qpow(Mat ret, int n) {
Mat ans;
for(int i = 0; i < 2; ++ i) {
ans.c[i][i] = 1;
}
while(n) {
if(n & 1) {
ans = ans * ret;
}
n >>= 1;
ret = ret * ret;
}
return ans;
}
int main() {
Mat ret;
ret.c[0][0] = 1;
ret.c[0][1] = 1;
ret.c[1][0] = 1;
int n;
while(cin >> n) {
if(n == 0) cout << 1 <<endl;
else if(n == 1) cout << 1 << endl;
else {
Mat pow_ret = qpow(ret, n - 1);
int f[2] = {1, 1}; //f[0]和f[1]
int ans = 0;
for(int i = 0; i < 2; ++ i) {
ans += f[i] * pow_ret.c[0][2 - i - 1];
}
cout << ans << endl;
}
}
}
再者,如果有常数,诸如
f(n)=f(n−1)+f(n−2)+C
f
(
n
)
=
f
(
n
−
1
)
+
f
(
n
−
2
)
+
C
,可通过化简转化为标准形式,上式与
f(n−1)=f(n−2)+f(n−3)+C
f
(
n
−
1
)
=
f
(
n
−
2
)
+
f
(
n
−
3
)
+
C
做差,即可得到
f(n)=2f(n−1)−f(n−3)
f
(
n
)
=
2
f
(
n
−
1
)
−
f
(
n
−
3
)
再者,如果带有幂函数,诸如
f(n)=f(n−1)+f(n−2)+xn
f
(
n
)
=
f
(
n
−
1
)
+
f
(
n
−
2
)
+
x
n
,可通过特征方程转化为标准形式