矩阵快速幂与斐波那契数列

矩阵快速幂与斐波那契数列

首先先说斐波那契数列,我们都知道它的递推式子是

n>=2 时f[n] = f[n-1]+f[n-2]

n = 1 时 f[1] = 1

n = 0 时 f[0] = 0

当题目让我们求一个斐波那契数列,比如n = 1000时,它变得非常大,所以通常题目会让我们求f[n]%mod。这样还能继续用递推做,但是……

当1<=n <= 1e9时,我们无法开这么大的数组,即使使用vector,o(n)的递推算法,也会让时间超限。那么,我们怎么从空间和时间上来求这么大的斐波那契数列呢?

 

首先你要具备线性代数中矩阵的有关知识~

矩阵的概念,性质,矩阵乘法等

 

知道矩阵乘法是怎么求得,那么代码怎么写呢?

比如有两个个矩阵A[m][t], B[t][n]  = C[m][n]  

代码:矩阵乘法

 

#include<bits/stdc++.h>
using namespace std;
struct mat
{
    int a[15][15];
    mat(){ //重载
        memset(a,0,sizeof(a));
    }
};
mat mul(mat x,mat y,int m,int n,int t)
{
    mat res;
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
        {
            for(int k=0;k<t;k++)
            {
                res.a[i][j] += x.a[i][k]*y.a[k][j];
            }
        }
    }
    return res;
}
int main()
{
    mat x,y;
    int m = 2,n=2,t = 3;    // 矩阵a[m][t]*b[t][n]
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<t;j++)
            cin>>x.a[i][j];
    }
    for(int i=0;i<t;i++)
    {
        for(int j=0;j<n;j++)
            cin>>y.a[i][j];
    }
    mat tmp = mul(x,y,m,n,t);
    for(int i=0;i<m;i++)
    {
        for(int j=0;j<n;j++)
            cout<<tmp.a[i][j]<<" ";
        cout<<endl;
    }
    return 0;
}

那么对于矩阵乘法与递推式之间的关系:

如:斐波那契数列

n>=2 时f[n] = f[n-1]+f[n-2]

n = 1 时 f[1] = 1

n = 0 时 f[0] = 0

证明:

我们把几个递推式写成以下形式:

f[n+1] = 1 * f[n] + 1 * f[n-1];

f[n] = 1 * f[n] + 0 * f[n-1];

f[n] = 1 * f[n-1] + 1 * f[n-2];

f[n-1] = 1 * f[n-1] + 0 * f[n-2];

我们把上述表达式转换成矩阵乘法

  • 式:

 = X

同理

  • 式:

 =  X

我们把②式带入①式

  = X

 

 

 

我们发现右式子左边的幂p和右边矩阵左上角的f[]的下标s具有关系 p+s = n+1

如:上式的2和n-1, n-1+2 = n+1 所以我们能通过这个恒关系,推出

 

 

结论:

 = X   

                                        =   (注:f[1]=f[2] = 1, f[0] = 0)

 

哇~(>ω<)我们发现通过求这个矩阵的n次方,就可以知道f[n]啦!

这里我就把推出来的 成为 基础矩阵 (个人习惯)

所以代码如下:d(d'')

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int M = 1e9+7;
typedef long long ll;
const int mod = 1e9+7;
int n ;
struct mat
{
    ll a[15][15];
    mat(){ //重载
        memset(a,0,sizeof(a));
    }
};
mat mul(mat x,mat y)
{
    mat res;
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
                res.a[i][j] = (res.a[i][j]+x.a[i][k]*y.a[k][j])%mod;
    return res;
}
ll qpow(int p)
{
    mat bas;//基础矩阵
    mat res;//单位矩阵
    for(int i=0;i<2;i++)
        res.a[i][i] = 1;
    bas.a[0][0] = bas.a[0][1] = bas.a[1][0] = 1;
    bas.a[1][1] = 0;
    while(p)
    {
        if(1&p) res = mul(res,bas);
        bas = mul(bas,bas);
        p>>=1;
    }
    return res.a[0][1];//或者res.a[1][0]
}
int main()
{
    cin>>n;
    cout<<qpow(n)<<endl; //f[n] = qpow(n)
    return 0;
}

 

 

 

猜你喜欢

转载自blog.csdn.net/qq_41661809/article/details/88648548