• 【洛谷P1962 斐波那契数列】矩阵快速幂+数学推导


    来提供两个正确的做法:

    • 斐波那契数列双倍项的做法(附加证明)
    • 矩阵快速幂

    一、双倍项做法

    在偶然之中,在百度中翻到了有关于斐波那契数列的词条(传送门),那么我们可以发现一个这个规律$ frac{F_{2n}}{F_{n}}=F_{n-1}+F_{n+1} $,那么我就想到了是不是可以用这个公式实现类似于快速幂之类的东西:power(n,m)=power(n*n,m/2) m mod 2=0 power(n,m)=power(n*n,m/2)*n m mod 2=1

    快速幂这个东西,是分成偶数情况和奇数情况,所以我们只是知道偶数想的计算公式,所以我们接下来要推导一下奇数项的递归式

    [F_{2n}=F_{n} imes(F_{n-1}+F_{n+1}) ]

    [F_{2n+2}=F_{n+1} imes(F_{n}+F_{n+2}) ]

    那么我们就是要从(F_{2n})(F_{2n+2})推导求出(F_{2n+1})

    [F_{2n+1}=F_{2n+2}-F_{2n} ]

    [F_{2n+1}=F_{n+1} imes(F_{n}+F_{n+2})-F_{n}*(F_{n-1}+F_{n+1}) ]

    [F_{2n+1}=F_{n+1} imes F_{n}+F_{n+1} imes F_{n+2} - F_{n} imes F_{n-1}-F_{n} imes F_{n+1} ]

    [F_{2n+1}=F_{n+1} imes F_{n+2}-F_{n} imes F_{n-1} ]

    [F_{2n+1}=F_{n+1} imes(F_{n+1}+F_{n})-F_{n} imes(F_{n+1}-F_{n}) ]

    [F_{2n+1}={F_{n+1}}^2+{F_{n}}^2 ]

    以上就是我们对于这个公式的推导
    那么我们就得到了

    **F[2n] = F[n+1]² - F[n-1]² = (2F[n-1] + F[n]) · F[n] **

    F[2n+1] = F[n+1]² + F[n]²

    那么,我们在写一个map,那么就可以不用全部都递归到底了,优化一下。
    用map映射一下大数,映射到我们的答案上。

    #include <bits/stdc++.h>
    using namespace std;
    const int Mod=1e9+7;//mod数
    long long n;
    map<long long,long long> ma;//搞映射
    inline long long work(long long x){
    	if(x==1||x==0)return 1;//边界
    	if(ma.count(x))return ma[x];//count如果是返回1那么就是这个答案已经在map中映射过了,0就是没有
    	long long res=0,t=x/2;
    	if(x&1) res=work(t)*(work(t-1)+work(t+1))%Mod;//公式2
    	else res=work(t)*work(t)%Mod+work(t-1)*work(t-1)%Mod;//公式1
    	return ma[x]=res;
    }
    int main() {//主程序
    	cin>>n;
    	long long res=work(n-1)%Mod;
    	cout<<res<<endl;
        return 0;
    }
    

    注:这个程序的复杂度是也差不多是log(n),也是非常优的解法


    二、矩阵乘法解法

    这个解法应该是这一道题的正解。

    我是一个蒟蒻,还是只是初懂矩阵乘法的小白。

    我就贴一下自己的代码,详细的题解还是看一下别的大佬的题解。

    #include <bits/stdc++.h>
    using namespace std;
    #define mod 1000000007 //Mod数
    struct Matrix{//这个是矩阵的结构体
        long long ma[2][2];
    };
    Matrix mul(Matrix A,Matrix B)//矩阵乘法
    {
        Matrix C;//答案矩阵
        C.ma[0][0]=C.ma[0][1]=C.ma[1][0]=C.ma[1][1]=0;//初始化
        for(int i=0;i<2;i++)
        {
            for(int j=0;j<2;j++)
            {
                for(int k=0;k<2;k++)
                {
                    C.ma[i][j]=(C.ma[i][j]+A.ma[i][k]*B.ma[k][j])%mod;
                }
            }
        }
        return C;
    }
    Matrix pow_mod(Matrix A,long long n)//卡苏米+矩阵乘法优化
    {
        Matrix B;
        B.ma[0][0]=B.ma[1][1]=1;
        B.ma[0][1]=B.ma[1][0]=0;
        while(n) {
            if(n&1) B=mul(B,A);
            A=mul(A,A);
            n>>=1;
        }
        return B;
    }
    int main()
    {
        long long n;
        Matrix A;
        A.ma[0][0]=1;A.ma[0][1]=1;
        A.ma[1][0]=1;A.ma[1][1]=0;//初始的数组
        Matrix ans=pow_mod(A,n);
        printf("%lld
    ",ans.ma[0][1]);//输出答案
        return 0;
    }
    

    注:关于矩阵乘法加速,这个矩阵有多种写法,这个只是其中的一种,不需要纠结于矩阵是否唯一。

  • 相关阅读:
    gdb 查看变量~p长串末尾省略号, 一个页面显示不完
    Git 在团队中的最佳实践--如何正确使用Git Flow[转]
    apktool+dex2jar+xjad反编译android程序
    浏览器缓存详解:expires,cache-control,last-modified,etag详细说明
    64位windows 7下成功配置TortoiseGit使用Github服务器
    github简单使用教程
    浅淡HTML5移动Web开发
    Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系
    深入浅出Symfony2
    利用PHP取二进制文件头判断文件类型
  • 原文地址:https://www.cnblogs.com/Dawn-Star/p/9807575.html
Copyright © 2020-2023  润新知