(这是博主的第一篇随笔,如有错误,敬请斧正)。
1:了解快速幂。
先把快速幂的代码呈上来。
这里要解释一下位运算‘&’和‘>>’。‘&’通常用于二进制取位操作,例如一个数 & 1 的结果就是取二进制的最末位。而‘>>’则是右移运算符,可以二进制去掉最后一位数字(相当于除二)。
那么,快速幂到底是什么意思?举个例子,计算9^10。常规的方法是循环10次,每次乘9,复杂度是O(N),而快速幂可以把复杂度降至log2N,计算时间明显下降。
计算原理:以求a^19为例。19的二进制数为10011=2^4+2^1+2^0。a^19=a*2^4*a*2^1*a*2^0;所以,要计算19次的幂被简化成只要计算几次,复杂度就没那么高了。幂运算很容易爆掉int,所以最好用long long或者unsigned int或者mod某个数。
2:矩阵快速幂。
矩阵快速幂的代码和快速幂十分接近,就只要多写一个矩阵相乘的算法,代码呈上(以快速求斐波拉契数列的第N项为例)。
斐波拉契数列的递推关系:F(n)=F(n-1)+F(n-2);得出递推关系,如图:
最后答案即为右边矩阵a[0][0]项,代码附下。
#include<iostream> #include<cstdio> #include<cstring> long long n; int i,j,k; const int mod=10000000; using namespace std; struct node { long long zjm[2][2]; void init()//将矩阵单位化(这一步相当于ans=1) { memset(zjm,0,sizeof(zjm)); for(i=0;i<2;i++) zjm[i][i]=1; } void initall()//将矩阵置零 { memset(zjm,0,sizeof(zjm)); } }; node mul(node a,node b) { node pro1; pro1.initall(); for(i=0;i<2;i++) { for(j=0;j<2;j++) { for(k=0;k<2;k++) { pro1.zjm[i][j]+=a.zjm[i][k]%mod*b.zjm[k][j]%mod;//矩阵乘法,注意i,j,k位置。 } } } return pro1; } node quickpower(node a,long long m) { node pro2; pro2.init(); while(m) { if(m&1) { pro2=mul(pro2,a); } a=mul(a,a); m>>=1; } return pro2; } int main() { node bas,s; bas.initall(); s.initall(); s.zjm[0][0]=s.zjm[0][1]=1;//zjm[0][0],zjm[0][1],分别储存F(2),F(1); bas.zjm[0][0]=bas.zjm[0][1]=bas.zjm[1][0]=1;//关联关系 while(scanf("%lld",&n)!=EOF) { node pro3=quickpower(bas,n-2); node answer; answer=mul(s,pro3); printf("%lld ",answer.zjm[0][0]); } }