快速矩阵幂解Fibonacci数列

快速幂运算

考虑求解一个数x的n次方:

线性方法:

long long f(int x,int n){
   long ans=1;
   while(n--){
     ans=*x
   }
   return ans;
}

显然此算法的时间复杂度为o(n);所以当n很大的时候,此算法的效率就显得很低下

接下来考虑对于一种更高效的算法,以n=22来观察

x^{n}=x^{\sum i}\ (\sum i=n)

此等式显然恒成立,接下来以n=22为例,在计算机中22的存储方式

很容易可以得到

x^{22}=x^{16}*x^{4}*x^{2}

回归到n上有

x^{n}=\prod x^{2^{i}*k}

其中i表示在二进制中对应的位数-1,k表示在i位上的取值(0\ or\ 1),于是有快速幂算法:

typedef long long ll;
ll mod_pow(ll x,ll n){
    ll ans =1;
    while(n>0){
      if(n&1) res*=x;
      x*=x;
      n >>= 1
    } 
    return ans; 
}

 Fibonacci数列

有如下数列:

1\ \ 1\ \ 2\ \ 3\ \ 5...

fib(n)=fib(n-1)+fib(n-2)\ \ \ \ (n\geq 3)

fib(n)=?

用递归的方式:

int fib(int n){
   if(n==1||n==2) return 1;
   return fib(n-1)+fib(n-2);
}

过程如下:

 显然有很多重复的计算,时间复杂度非常大,即使利用备忘录或者一个循环来解决,此时的复杂度仍O(n),很多情况下依旧不能接受。

于是考虑快速矩阵幂:

\because fib(n)=fib(n-1)+fib(n-2)\ \ \ \ (n\geq 3)

于是可以构造如下矩阵

\bigl(\begin{smallmatrix}F_{n+2} \\ F_{n+1} \end{smallmatrix}\bigr)= \bigl(\begin{smallmatrix}1 &1 \\ 1& 0 \end{smallmatrix}\bigr) \bigl(\begin{smallmatrix}F_{n+1} \\ F_{n} \end{smallmatrix}\bigr)

可能会有一点跳跃,但是联系矩阵乘法的本质,还是很好理解的!!!

记录这个矩阵为A,于是有:

\begin{pmatrix} F_{n+1}\\ F_{n} \end{pmatrix}=A^{n}\begin{pmatrix} F_{1}\\ F_{0} \end{pmatrix}=A^{n}\begin{pmatrix} 1\\ 0 \end{pmatrix}

(F_{0}倒退可知为0)

因此只要求A^{n} 就可以求出F_{n},A^{n}的计算参考上面的快速幂,此算法可在O(logn)时间内求出第n项

//用二维vector表示矩阵
typedef vector<int> vec;
typedef vector<vec> mat;

const int M=1<<5;

//计算A*B
mat mul(mat&A,mat&B){
    mat C(A.size(),vec(B[0].size()));
    for(int i=0;i<A.size();i++){
       for(int k=0;k<B.size();k++){
         for(int j =0;j<B[0].size();j++){
            c[i][j]=(c[i][j]+A[i][k]*B[k][j])%M;

         }
       }
     }
    return C;  
}

//计算A^n
mat pow(mat A,ll n){
  mat B(A.size(),vec(A.size()));
  for(int i=0;i<A.size();i++){
    B[i][i]=1;
  }
  while(n>0){
    if(n&1) B=mul(B,A);
    A=mul(A,A);
    n>>=1;
  }
  return B;
}

//输入
ll n;

void solve(){
  mat A(2,vec(2));
  A[0][0]=1;A[0][1]=1;
  A[1][0]=1;A[1][1]=0;
  A=pow(A,n);
  cout<<A[1][0];
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值