hdu 5667(矩阵快速幂)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5667

题意:给出一个递推式求解fn的值。

分析:因为是递推,很容易联想到矩阵快速幂。但本题的式子是一个乘法,所以就采用求对数然后就变成加法了。当然本题求完对数后腰用费尔马小定理来求解a的b次方,因为求对数,最后还要求回指数。本题求完对数的公式为f(n)=(b+f(n-1)*c+f(n-2))mod p-1;f1=0;f2=b;

最终结果为 a^(f(n))%p;

代码如下:

#include <set>
#include <map>
#include <stack>
#include <queue>
#include <math.h>
#include <vector>
#include <string>
#include <utility>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;
struct Matrax{
    long long m[10][10];
}ter;
long long mod;
Matrax muli(Matrax a,Matrax b){
    Matrax p;
    for(int i=0;i<3;i++)
    for(int j=0;j<3;j++){
        p.m[i][j]=0;
        for(int k=0;k<3;k++){
            p.m[i][j]+=(a.m[i][k]*b.m[k][j])%(mod-1);
            p.m[i][j]%=mod-1;
        }
    }
    return p;
}//矩阵乘法
Matrax quick_mod(Matrax a,long long b){
    Matrax ans=ter;
    while(b){
        if(b&1){
            ans=muli(ans,a);
            b--;
        }
        else {
            b>>=1;
            a=muli(a,a);
        }
    }
    return ans;
}//快速幂
long long qmod(long long a,long long b){
    long long ans=1;
    while(b){
        if(b&1){
            ans=ans*a%mod;
            b--;
        }
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        long long n,a,b,c;
        scanf("%I64d%I64d%I64d%I64d%I64d",&n,&a,&b,&c,&mod);
        if(n==1){
            puts("1");
            continue;
        }
        if(n==2){
            printf("%I64d\n",qmod(a,b));
            continue;
        }
        ter.m[0][0]=1;
        ter.m[0][1]=0;
        ter.m[0][2]=0;
        ter.m[1][0]=0;
        ter.m[1][1]=1;
        ter.m[1][2]=0;
        ter.m[2][0]=0;
        ter.m[2][1]=0;
        ter.m[2][2]=1;//初始化E矩阵   因为本题推出来是三元相加,所以用三维矩阵
        n-=2;
        Matrax A,B;
        A.m[0][0]=0;
        A.m[0][1]=1;
        A.m[0][2]=0;
        A.m[1][0]=1;
        A.m[1][1]=c;
        A.m[1][2]=0;
        A.m[2][0]=0;
        A.m[2][1]=b;
        A.m[2][2]=1;//这里是中间连乘部分的矩阵
        A=quick_mod(A,n);
        B.m[0][0]=0;
        B.m[0][1]=b;
        B.m[0][2]=1;
        B.m[1][0]=0;
        B.m[1][1]=0;
        B.m[1][2]=0;
        B.m[2][0]=0;
        B.m[2][1]=0;
        B.m[2][2]=0;
        B=muli(B,A);//这里是最初始的矩阵
//        cout<<B.m[0][1]<<endl;
//        cout<<a<<endl;
        printf("%I64d\n",qmod(a,B.m[0][1]+mod-1));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值