2020牛客寒假算法基础集训营1----J-u's的影响力 (费马小定理+矩阵快速幂)

题目链接:https://ac.nowcoder.com/acm/contest/3002/J

题意:给出一个递推式: f[i]=f[i-2] * f[i-1] * ab。并且 f[1] = x , f[2] = y , 其中x,y,a,b<=1e12,求第n项f[n]。(n<=1e12

思路:

  首先列出前几项的表达式如下:

 

   我们可以发现根据递推式发现,x的系数:fx(i) = fx(i-2) +fx(i-1),y的系数:fy(i) = fy(i-2) +fy(i-1),a的系数:fa(i) = fa(i-2) +fa(i-1)+b。于是可以用矩阵快速幂来求系数。然后根据费马小定理知道矩阵快速幂过程中的模数MODD=1e9+6

AC代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int MOD=1e9+7;
const int MODD=1e9+6;
typedef long long LL;
LL n,x,y,a,b;
int up;

struct Mat{
    LL m[5][5];
    Mat(){memset(m,0,sizeof(m));}
};

LL qpow(LL a,LL b){
    LL ret=1;
    a%=MOD;
    while(b){
        if(b&1) ret=ret*a%MOD;
        a=a*a%MOD;
        b>>=1;
    }
    return ret;
}

Mat Matmul(Mat a,Mat b){
    Mat ret;
    for(int i=1;i<=up;++i)
        for(int j=1;j<=up;++j)
            for(int k=1;k<=up;++k){
                ret.m[i][j]+=a.m[i][k]*b.m[k][j]%MODD;
                ret.m[i][j]%=MODD;
            }
    return ret;
}

Mat Matqpow(Mat a,LL b){
    Mat ret;
    for(int i=1;i<=up;++i) ret.m[i][i]=1;
    while(b){
        if(b&1) ret=Matmul(ret,a);
        a=Matmul(a,a);
        b>>=1;
    }
    return ret;
}

int main(){
    scanf("%lld%lld%lld%lld%lld",&n,&x,&y,&a,&b);
    x%=MOD,y%=MOD,a%=MOD,b%=MOD-1;
    if(n==1){
        printf("%lld\n",x);
        return 0;
    }
    else if(n==2){
        printf("%lld\n",y);
        return 0;
    }
    else if(x==0||y==0||a==0){
        printf("0\n");
        return 0;
    }
    else{
        up=2;
        Mat mx1,mx2;
        mx1.m[1][1]=mx1.m[1][2]=mx1.m[2][1]=1;
        mx2.m[2][1]=1;
        mx1=Matqpow(mx1,n-2);
        mx1=Matmul(mx1,mx2);
        LL res1=qpow(x,mx1.m[1][1]);

        Mat my1,my2;
        my1.m[1][1]=my1.m[1][2]=my1.m[2][1]=1;
        my2.m[1][1]=1;
        my1=Matqpow(my1,n-2);
        my1=Matmul(my1,my2);
        LL res2=qpow(y,my1.m[1][1]);

        up=3;
        Mat ma1,ma2;
        ma1.m[1][1]=ma1.m[1][2]=ma1.m[1][3]=ma1.m[2][1]=ma1.m[3][3]=1;
        ma2.m[3][1]=b;
        ma1=Matqpow(ma1,n-2);
        ma1=Matmul(ma1,ma2);
        LL res3=qpow(a,ma1.m[1][1]);

        LL ans=res1*res2%MOD*res3%MOD;
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2020-02-07 15:27  Frank__Chen  阅读(205)  评论(0编辑  收藏  举报