zoukankan      html  css  js  c++  java
  • 简单的斐波那契

    广义斐波那契

    与原来的斐波那契类似

    递推的公式有所变化

    如果直接线性递推,O(n)的复杂度,在很多题目中都会被卡,所以这时候就可以用矩阵吗快速幂复杂度是O(logn)的

    比照普通的快速幂,矩阵快速幂就是一样的思路

    ll quick_pow(ll a,ll b,ll p)
    {
       ll ans=1;
       while (b)
       {
         if (b&1)  ///b为奇数
            ans=(ans*a)%p;
         a=(a*a)%p; ///b为偶数
         b>>=1;
       }
       return ans;
    }
    

    乘以

    就可以得到

    所以只要把

    乘以的n-1次方就可以得到FN Fn+1,而矩阵快速幂就可以快速求出后面的矩阵的n-1次方


    模板题

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int mod=1e9+7;
    ll n,k;
    struct Node {
       ll a[101][101];
    }ret,tmp;
    Node chen(Node x,Node y)
    {
        Node D;
        for (int i=1;i<=2;++i)
            for (int j=1;j<=2;++j)D.a[i][j]=0;
        for (int i=1;i<=2;++i)
            for (int j=1;j<=2;++j)
                for (int k=1;k<=2;++k)
                    D.a[i][j]=(D.a[i][j]%mod+(x.a[i][k]*y.a[k][j])%mod)%mod;///基本的矩阵乘法
                    return D;
    
    }
    Node quick_chen(ll b,Node z)
    {
        Node s=tmp;///首先要开个单位矩阵,保证开始的乘法不变
        while (b)
        {
           if (b&1)  s=chen(s,z);///b为奇数,更新s
           z=chen(z,z);
           b>>=1;
        }
        return s;
    }
    
    int main()
    {
        ll n;
        scanf("%lld",&n);
        tmp.a[1][1]=1ll;
        tmp.a[2][2]=1ll;///2*2的单位矩阵
        Node Z;
        Z.a[1][2]=1ll;
        Z.a[2][1]=1ll;
        Z.a[2][2]=1ll;///初始化
        Node Q=quick_chen(n-1,Z);///1 1
        printf("%lld
    ",((Q.a[1][1]+Q.a[2][1])%mod*1ll*(Q.a[1][2]+Q.a[2][2])%mod)%mod);
        return 0;
    }
    
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    ll mod=1e9+7;
    struct Node {
      long long  a[10][10];
        Node(){
            for (int i=1;i<=2;++i)
              for(int j=1;j<=2;++j)
                 if(i==j) a[i][j]=1ll;
                 else a[i][j]=0;
            }
    }tmp;
    Node chen(Node x,Node y)
    {
        Node D;
        for (int i=1;i<=2;++i)
            for (int j=1;j<=2;++j)D.a[i][j]=0;
        for (int i=1;i<=2;++i)
            for (int j=1;j<=2;++j)
                for (int k=1;k<=2;++k)
                    D.a[i][j]=(D.a[i][j]%mod+(x.a[i][k]%mod*y.a[k][j]%mod)%mod)%mod;
                    return D;
    
    }
    Node quick_chen(long long b,Node z)
    {
        Node s=tmp;
        while (b)
        {
           if (b&1)  s=chen(s,z);
           z=chen(z,z);
           b>>=1;
        }
        return s;
    }
    int main()
    {
        ll b,c,p,q,n,m;
        scanf("%lld%lld%lld%lld%lld%lld",&b,&c,&p,&q,&n,&m);///an=b*an-1+c*an-2  p=an-1 q=an-2  m=mod
        mod=m;
        Node Z;
        Z.a[1][1]=0;
        Z.a[1][2]=c%mod;
        Z.a[2][1]=1ll;
        Z.a[2][2]=b%mod;
        Node Q=quick_chen(n-1,Z);///1 1
        printf("%lld
    ",(Q.a[1][1]*p%mod+Q.a[2][1]*q%mod)%mod);
        return 0;
    }
    
    

    当然按照之前的想法,斐波那契有着递推公式

    给一个简单的证明

    带根号也许不好处理,但是遇到取模的操作也就可以用上根号,譬如根号5,用二次剩余

    令N=5,也就是x=根号5 求解出的x取模和原本的根号5取模等价,就直接先求出2的逆元,然后拆分成1和根号5按照之前的步骤二次剩余根号5也就是(1+根号5等价的数)*2的逆元%p

    但是局限性很大,mod 1e9+9二次剩余还有解,但是1e9+7就不存在根号5的二次剩余了,权当一种思路

    齐芒行,川锋明!
  • 相关阅读:
    sphinx安装
    如何获取原生数据
    DOM详解
    JavaScript简单入门(补充篇)
    JavaScript的简单入门
    Java正则表达式练习
    Java反射机制(Reflect)解析
    21070118记
    CSS3设置Table奇数行和偶数行样式
    获取当前地址
  • 原文地址:https://www.cnblogs.com/qimang-311/p/13418193.html
Copyright © 2011-2022 走看看