矩阵快速幂
矩阵快速幂可以将数列求通项问题用 O l o g n Olog{n} Ologn的时间复杂度求出
看个例子:
题目简述:
有通项公式:
a
n
=
1
,
n
∈
{
1
,
2
,
3
}
a_n=1,n\in\{1,2,3\}
an=1,n∈{1,2,3}
a
n
=
a
n
−
1
+
a
n
−
3
a_n=a_{n-1}+a_{n-3}
an=an−1+an−3
求第n项的值,并对 1 0 9 + 7 10^{9}+7 109+7取余
数据范围:
1 ≤ n ≤ 1 0 9 1\leq n\leq10^9 1≤n≤109
显然,我们不能暴力递归,即使用动归的方式也只能将复杂度降到
O
(
N
)
O(N)
O(N)
也会TLE。
我们可以试着列出前几项,这里我是从0开始编号的。
a
i
=
0
,
1
,
1
,
1
,
2
,
3
,
4
,
6
,
.
.
.
.
.
.
,
i
∈
{
0
,
1
,
2
,
.
.
.
n
}
{a_i} = {0 , 1 , 1 , 1 , 2 , 3 , 4 , 6 , ......} , i\in{\{0 , 1 , 2 ,...n\}}
ai=0,1,1,1,2,3,4,6,......,i∈{0,1,2,...n}
a
0
=
0
,
a
1
=
1
,
a
2
=
1
,
a
3
=
1
,
a
4
=
2.....
a_0 = 0 , a_1 = 1 , a_2 = 1 , a_3 = 1 , a_4 = 2.....
a0=0,a1=1,a2=1,a3=1,a4=2.....以此类推
我们把递推公式转换为线性代数里矩阵相乘形式。
通过题目给出的通向公式,我们可以得到:
f
[
i
−
2
]
=
0
×
f
[
i
−
2
]
+
1
×
f
[
i
−
1
]
+
0
×
f
[
i
]
f[i-2]=0\times f[i-2]+1\times f[i-1]+0\times f[i]
f[i−2]=0×f[i−2]+1×f[i−1]+0×f[i]
f
[
i
−
1
]
=
0
×
f
[
i
−
2
]
+
0
×
f
[
i
−
1
]
+
1
×
f
[
i
]
f[i-1]=0\times f[i-2]+0\times f[i-1]+1\times f[i]
f[i−1]=0×f[i−2]+0×f[i−1]+1×f[i]
f
[
i
]
=
1
×
f
[
i
−
2
]
+
0
×
f
[
i
−
1
]
+
1
×
f
[
i
]
f[i]=1\times f[i-2]+0\times f[i-1]+1\times f[i]
f[i]=1×f[i−2]+0×f[i−1]+1×f[i]
由此我们容易得出矩阵乘的形式:
[
0
1
0
0
0
1
1
0
1
]
(!)
\begin{bmatrix} 0 & 1 & 0 \\ 0 & 0 & 1 \\ 1 & 0 & 1 \end{bmatrix} \tag{!}
001100011
(!)
[ 0 1 1 ] (*) \begin{bmatrix} 0 \\ 1 \\ 1 \end{bmatrix} \tag{*} 011 (*)
令 (!) = M , (*) = ans;
问题就转化为了 M n × a n s = a n M^n\times ans=a_n Mn×ans=an
M n M^{n} Mn可以用快速幂的思想求解
Code
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
struct matrix{
ll mt[5][5];
}ans , pre , E;
void init(){
memset(E.mt , 0 , sizeof E.mt);
for (int i = 0 ; i < 3 ; ++ i) E.mt[i][i] = 1;
memset(ans.mt , 0 , sizeof ans.mt);
for (int i = 1 ; i < 3 ; ++ i) ans.mt[i][0] = 1;
memset(pre.mt , 0 , sizeof pre.mt);
pre.mt[0][1] = pre.mt[1][2] = pre.mt[2][0] = pre.mt[2][2] = 1;
}
matrix mul(matrix a , matrix b){
matrix ans;
memset(ans.mt , 0 , sizeof ans.mt);
for (int i = 0 ; i < 3 ; ++ i)
for (int j = 0 ; j < 3 ; ++ j)
for (int k = 0 ; k < 3 ; ++ k){
ans.mt[i][j] += a.mt[i][k] % mod * b.mt[k][j] % mod;
ans.mt[i][j] %= mod;
}
return ans;
}
matrix qmi(int b){
while(b){
if (b & 1) E = mul(pre , E);
pre = mul(pre , pre);
b >>= 1;
}
ans= mul(E , ans);
}
int main(){
int t;
scanf ("%d" , &t);
while (t -- ){
int n;
scanf ("%d" , &n);
if (n <= 3){
puts("1");
continue;
}
init();
qmi(n - 2);
cout << ans.mt[2][0] << endl;
}
return 0;
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了矩阵快速幂的使用。
矩阵快速幂不过是快速幂的矩阵形式,如果事先有过快速幂的学习,理解矩阵快速幂就非常快了.