# 矩阵快速幂 计算Fibonacci数列(2020牛客1.J)

J. u's的影响力

题目:

​ 输入\(n,x,y,a,b\) 。输出 \(x^{f(n-2)}*y^{f(n-1)}*a^{[f(n)-1]*b}\) .其他f(i)表示Fibonacci数值

题解:

  • 通过观察前几项得到上面的公式。利用矩阵快速幂可以计算很大的Fibonacci数,然后用快速幂求结果。
  • 快速幂中,如果x是模数的倍数,那么对于x=0,y=0的情况,qpow(0,0) = 1,但是应该输出0,这一点要特判一下。
  • 根据费马小定理,若 \(p\) 是正数,则对任意整数 \(a\) ,有 \(a^{p} \equiv a \ (mod \ p)\) 。两边同时除 \(a\) 得, \(a^{p-1} \equiv 1 \ (mod \ p)\) . 所以可以通过对幂取模来实现降幂。

推荐博客:矩阵构造方法

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MA=1e5+5;
const ll mod=1e9+7;
const ll P=1e9+6;

struct mat{
    ll m[3][3];
    mat(){memset(m,0,sizeof(m));}
};

mat mul(mat x,mat y){   //矩阵乘法
    mat res;
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j)
            for(int k=0;k<3;++k)
                res.m[i][j]=(res.m[i][j]+x.m[i][k]*y.m[k][j])%P;
    return res;
}

mat power(mat A, ll n){ //矩阵快速幂
    mat c=A,res;
    for(int i=0;i<3;++i) res.m[i][i]=1;
    while(n){
        if(n&1) res=mul(res,c);
        c=mul(c,c);
        n>>=1;
    }
    return res;
}

ll qpow(ll x,ll y){ //快速幂
    if(x%mod==0) return 0;
    ll res=1;
    while(y){
        if(y&1) res=(res*x)%mod;
        x=(x*x)%mod;
        y>>=1;
    }
    return res;
}


ll n,x,y,a,b;

int main()
{
    scanf("%lld%lld%lld%lld%lld",&n,&x,&y,&a,&b);
    x%=mod, y%=mod, a%=mod , b%=P;
    if(n == 1) printf("%lld\n",x);
    else if(n == 2) printf("%lld\n",y);
    else{
        mat A,B,C;          //辅助矩阵
        ll f1,f2,f3;        //辅助变量,存三个Fibonacci值
        A.m[0][0] = 1, A.m[0][1] = 1, A.m[1][0] = 1;
        B.m[0][0] = 0, B.m[1][0] = 1;
        
        
        C=mul(power(A,n-2) , B);    //计算F(n-2)
        f1=C.m[0][0] ;
        
        C=mul(power(A,n-1) , B);    //计算F(n-1)
        f2=C.m[0][0] ;
        
        C=mul(power(A,n) , B);      //计算F(n);
        f3=b*(C.m[0][0] -1 +P ) %P;

        printf("%lld\n",qpow(x,f1)%mod *qpow(y,f2)%mod * qpow(a,f3)%mod);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/A-sc/p/12275039.html