HDU 3221 Brute-force Algorithm

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

思路:

稍微开个脑洞想想,就能发现递推式是f(n)=f(n-1)*f(n-2),再想想就能想到可通过先计算a用了多少次,b用了多少次来计算,最后套一个快速幂来计算f(n),在计算a用了多少次的时候又可以发现,a的次数其实是一个斐波那契数,但是在计算a的次数的时候会发现这个次数会爆long long并且不能简单的来用P进行取模,怎么办呢? 怎么办呢? 想了好久后来才知道这个地方有一个公式:

(a^b)%mo=(a^(b%phi[mo]+phi[mo]))%mo  b>=phi[mo]

用这个公式在矩阵快速幂的时候对b进行取模就好(ps:不是直接对phi[mo]取模~~~)

code:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;

typedef long long LL;

typedef vector<LL> vec;
typedef vector<vec> mat;

LL mo,mod;

LL mod_pow(LL x,LL n)
{
    LL res=1;
    while(n>0){
        if(n&1) res=res*x%mo;
        x=x*x%mo;
        n>>=1;
    }
    return res;
}

mat mul(mat &A,mat &B)
{
    mat C(A.size(),vec(B[0].size()));
    for(int i=0;i<A.size();i++){
        for(int k=0;k<B.size();k++){
            for(int j=0;j<B[0].size();j++){
                C[i][j]=C[i][j]+A[i][k]*B[k][j];
                if(C[i][j]>mod) C[i][j]=C[i][j]%mod+mod;
            }
        }
    }
    return C;
}

mat pow(mat A,LL n)
{
    mat B(A.size(),vec(A.size()));
    for(int i=0;i<A.size();i++) B[i][i]=1;
    while(n>0){
        if(n&1) B=mul(B,A);
        A=mul(A,A);
        n>>=1;
    }
    return B;
}

LL euler(LL x)
{
    LL i, res = x;
    for (i = 2; i*i <= x; i++)
    {
        if (x%i == 0)
        {
            res = res / i*(i - 1);
            while (x%i == 0)
                x /= i;
        }
    }
    if (x > 1)
        res = res / x*(x - 1);
    return res;
}


int main()
{
    LL a,b,n,m1,m2,res;
    int T;
    scanf("%d",&T);
    for(int kk=1;kk<=T;kk++){
        scanf("%I64d%I64d%I64d%I64d",&a,&b,&mo,&n);
        printf("Case #%d: ",kk);
        //if(mo==1) printf("0\n");
        //else if(n==1) printf("%I64d\n",a%mo);
        //else if(n==2) printf("%I64d\n",b%mo);
        //else{
        mod=euler(mo);
        mat A(2,vec(2));
        A[0][0]=A[0][1]=1;
        A[1][0]=1;A[1][1]=0;
        A=pow(A,n-1);
        m1=A[1][1];
        if(m1>=mod) m1=m1%mod+mod;
        m2=A[1][0];
        //cout<<m1<<" "<<m2<<endl;
        if(m2>=mod) m2=m2%mod+mod;
        res=(mod_pow(a,m1)*mod_pow(b,m2))%mo;
        printf("%I64d\n",res);
       // }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值