矩阵快速幂
矩阵快速幂其实原理上和快速幂是一样的,只不过基数是一个矩阵。常用于解决常系数齐次线性递推式一类的问题,这类问题通常需要自己构造矩阵。
下面举两个例子:
1.先是最简单的Fibonacci数列,
,求第n项,当n非常大的时候按原来的递推已经不能解决了,时间上不允许,空间上也不允许。
,左边的矩阵第一行放
的各项,右边的矩阵第一行放
的各项,注意
有
项加起来,构造出来的就是
的矩阵。
求解矩阵
满足上式
构造方法:
其中
就能用矩阵快速幂解决了。
2.再来一个:
,求第n项。
思路和上一个一样:
注意:因为每次都要取模p,所以要求
,就要求出a关于p的逆元,还要注意的的是最后得出来的矩阵的
项要除以a才是
,此时又要求逆元。。。
最后码上矩阵快速幂的模板:
求Fibonacci数列第n项
#include<cstdio>
#include<set>
#include<map>
#include<string.h>
#include<string>
#include<vector>
#include<iostream>
#include<queue>
#include<algorithm>
typedef long long LL;
using namespace std;
const int maxn=1e6+5;
const int mod=10000;
struct node
{
LL mat[2][2];
node(LL a,LL b,LL c,LL d){
mat[0][0]=a;
mat[0][1]=b;
mat[1][0]=c;
mat[1][1]=d;
}
};
node operator * (node a,node b)//重载*号
{
node ans(0,0,0,0);
LL sum=0;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
sum=0;
for(int k=0;k<2;k++){
sum+=(a.mat[i][k]%mod*b.mat[k][j]%mod)%mod;
sum%=mod;
}
ans.mat[i][j]=sum;
}
}
return ans;
}
node POW(node a,LL b)
{
node ans(1,0,0,1);
while(b){
if(b&1)ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
int main()
{
LL n;
while(scanf("%lld",&n)&&n!=-1){
node a(1,1,1,0);
node ans=POW(a,n);
printf("%lld\n",ans.mat[0][1]);
}
return 0;
}