关于快速幂
可参考以下博客:
快速幂算法
关于构造矩阵
可参考以下两篇博客:
矩阵构造方法
根据递推公式构造系数矩阵用于快速幂
以斐波那契数列为例
f
[
n
]
=
f
[
n
−
1
]
+
f
[
n
−
2
]
(
f
[
1
]
=
f
[
2
]
=
1
)
f[n]=f[n-1]+f[n-2]\quad (f[1]=f[2]=1)
f[n]=f[n−1]+f[n−2](f[1]=f[2]=1)
我们可得
f
[
n
]
=
1
×
f
[
n
−
1
]
+
1
×
f
[
n
−
2
]
f[n]=1\times f[n-1]+1\times f[n-2]
f[n]=1×f[n−1]+1×f[n−2]
f
[
n
−
1
]
=
1
×
f
[
n
−
1
]
+
0
×
f
[
n
−
2
]
f[n-1]=1\times f[n-1]+0\times f[n-2]
f[n−1]=1×f[n−1]+0×f[n−2]
进行矩阵构造
[
f
[
n
]
f
[
n
−
1
]
]
=
[
1
1
1
0
]
×
[
f
[
n
−
1
]
f
[
n
−
2
]
]
\left[ \begin{matrix} f[n] \\ f[n-1] \\ \end{matrix} \right]=\left[ \begin{matrix} 1 &1 \\ 1 & 0 \\ \end{matrix} \right]\times \left[ \begin{matrix} f[n-1] \\ f[n-2] \\ \end{matrix} \right]
[f[n]f[n−1]]=[1110]×[f[n−1]f[n−2]]
×
\times
×左面矩阵为
f
[
n
]
,
f
[
n
−
1
]
f[n],f[n-1]
f[n],f[n−1]等式右侧系数,右侧为等号右侧的项,我们可使用以上式子进行递推,设
×
\times
×左边矩阵为
A
A
A,则最后可得
f
[
n
]
=
A
n
−
2
[
f
[
2
]
f
[
1
]
]
f[n]=A^{n-2}\left[ \begin{matrix} f[2] \\ f[1] \\ \end{matrix} \right]
f[n]=An−2[f[2]f[1]]
设
A
n
−
2
A^{n-2}
An−2为
B
B
B,则
f
[
n
]
=
B
1
1
+
B
1
2
f[n]=B_{1\,1}+B_{1\,2}
f[n]=B11+B12
矩阵快速幂中,最核心的是计算出基础矩阵A。要满足K阶常系数线性递推关系。
以下为两道例题:
P3390 【模板】矩阵快速幂
题目链接
代码
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int maxn=105,p=1e9+7 ;
int n;
ll k ;
struct ymatrix
{
ll a[maxn][maxn] ;
}A ;
inline ll read()
{
ll x=0,f=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}
while(c<='9'&&c>='0') {x=x*10+c-'0'; c=getchar();}
return f*x;
}
ymatrix mul ( ymatrix a , ymatrix b )
{
ymatrix ans ;
for ( int i = 1 ; i <= n ; ++i )
for ( int j = 1 ; j <= n ; ++j)
{
ans.a[i][j] = 0 ;
for ( int k = 1 ; k <= n ; ++k )
{
ans.a[i][j] += a.a[i][k] * b.a[k][j] ;
ans.a[i][j] %= p ;
}
}
return ans ;
}
ymatrix quickpow( ymatrix a , ll b )
{
ymatrix ans , base = a ;
for ( int i = 1 ; i <= n ; ++i )
for ( int j = 1 ; j <= n ; ++j )
ans.a[i][j] = 0 ;
for ( int i = 1 ; i <= n ; ++i ) ans.a[i][i] = 1 ;
while ( b )
{
if ( b & 1 ) ans = mul ( ans , base ) ;
base = mul ( base , base ) ;
b >>= 1 ;
}
return ans ;
}
int main()
{
scanf("%d",&n) ; k = read() ;
for ( int i = 1 ; i <= n ; ++i )
for ( int j = 1 ; j <= n ; ++j )
A.a[i][j] = read() ;
ymatrix ans = quickpow(A,k) ;
for ( int i = 1 ; i <= n ; ++i )
{
for ( int j = 1 ; j <= n ; ++j )
printf("%lld ",ans.a[i][j]) ;
printf("\n") ;
}
return 0 ;
}
P1962 斐波那契数列
题目链接
代码
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int maxn=5,p=1e9+7 ;
ll n;
struct ymatrix
{
ll a[maxn][maxn] ;
}A ;
inline ll read()
{
ll x=0,f=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}
while(c<='9'&&c>='0') {x=x*10+c-'0'; c=getchar();}
return f*x;
}
ymatrix mul ( ymatrix a , ymatrix b )
{
ymatrix ans ;
for ( int i = 1 ; i <= 2 ; ++i )
for ( int j = 1 ; j <= 2 ; ++j)
{
ans.a[i][j] = 0 ;
for ( int k = 1 ; k <= 2 ; ++k )
{
ans.a[i][j] += a.a[i][k] * b.a[k][j] ;
ans.a[i][j] %= p ;
}
}
return ans ;
}
ymatrix quickpow( ymatrix a , ll b )
{
ymatrix ans , base = a ;
for ( int i = 1 ; i <= 2 ; ++i )
for ( int j = 1 ; j <= 2 ; ++j )
ans.a[i][j] = 0 ;
for ( int i = 1 ; i <= 2 ; ++i ) ans.a[i][i] = 1 ;
while ( b )
{
if ( b & 1 ) ans = mul ( ans , base ) ;
base = mul ( base , base ) ;
b >>= 1 ;
}
return ans ;
}
int main()
{
n = read() ;
if( n == 1 || n == 2 ) printf("1\n") ;
else
{
A.a[1][1] = A.a[1][2] = A.a[2][1] = 1 ;
A.a[2][2] = 0 ;
ymatrix ans = quickpow( A , n-2 ) ;
printf("%lld\n",(ans.a[1][1] + ans.a[1][2]) % p) ;
}
return 0 ;
}
总结与反思
- 计算中要注意是否超出数据结构,最好使用 l o n g l o n g long \ long long long
- 掌握构造矩阵的方法,刚接触时难免不熟悉,多推一推就能较好掌握了
- 注意全局变量是否与函数内变量冲突

2340





