简单的斐波那契

广义斐波那契

与原来的斐波那契类似

递推的公式有所变化

如果直接线性递推,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\n",((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\n",(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的二次剩余了,权当一种思路

posted @ 2020-08-02 11:15  齐芒  阅读(149)  评论(0)    收藏  举报