矩阵快速幂

(这是博主的第一篇随笔,如有错误,敬请斧正)。

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]);
  }
}
原文地址:https://www.cnblogs.com/switch-waht/p/10602627.html