hdu 3221 欧拉定理 +快速幂+矩阵快速幂

首先这道题考的是递归调用的计数问题

最终返回时分别是1时执行a次和2时执行b次,根据计数原理:

根据递归的调用机制和排列组合的乘法原则,得出f[n]=f[n-1]*f[n-2];

而递归的增长随着是指数增长的,所以f[n-1]*f[n-2]又可以转换成同底的指数形式,进而转化成指数的想家,可以联想到斐波那契数列的性质.

利用动态规划的思想进行,通过矩阵快速幂和快速幂进行优化;

然后就是同余的问题,在指数很大的情况下,可以利用欧拉定理降次;

A^x  = A^(x%phi+phi)mod p

在应用同余定理,这道题就很容易解决了.

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long LL;

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

mat multi ( mat a , mat b , LL mod  )
{
    mat c;
    for ( LL i = 1 ; i < 3 ; i++ )
        for ( LL j = 1 ; j < 3 ; j++ )
            if ( a.m[i][j] )
                for ( LL k = 1 ; k < 3 ; k++ )
                    c.m[i][k] = ( c.m[i][k] + a.m[i][j]*b.m[j][k] )%mod;
    return c;
}

mat quickmulti ( mat a , LL n , LL mod )
{
    mat ans;
    for ( LL i = 1 ; i < 3 ; i++ ) ans.m[i][i] = 1;
    while ( n )
    {
        if ( n&1 ) ans = multi ( ans , a, mod );
        a = multi ( a , a , mod );
        n >>= 1;
    }
    return ans;
}

LL pow ( LL num , LL n , LL mod )
{
    LL ans = 1;
    while ( n )
    {
        if ( n&1 ) ans = ( ans * num )%mod;
        num = (num*num)%mod;
        n>>=1;
    }
    return ans;
}

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

LL index ( LL n , LL phi )
{
    int a = 1 , b = 0 , temp , i ;
    for ( i = 1 ; i <= n ; i++ )
    {
        temp = a + b;
        b = a;
        a = temp;
        if ( temp >= phi ) break;
    }
    if ( i > n )
       return a; 
    mat ma,mb;
    ma.m[1][1] = mb.m[1][1] = mb.m[1][2] = mb.m[2][1] = 1;
    mb = quickmulti ( mb , n , phi );
    ma = multi ( ma , mb , phi );
    return ma.m[1][1]%phi + phi;
}

int t ;
LL a , b , p , n;

int main ( )
{
    scanf ( "%d" , &t );
    int c = 0;
    while ( t-- )
    {
        c++;
        scanf ( "%lld%lld%lld%lld" , &a , &b , &p , &n );
        printf ( "Case #%d: ",c );
        if ( a == 0 || b == 0 )
        {
            printf ( "0\n");
            continue;
        }
        if ( n == 1 )
        {
            printf ( "%I64d\n" , a%p );
            continue;
        }
        if ( n == 2 )
        {
            printf ( "%I64d\n" , b%p );
            continue;
        }
        if ( p == 1 )
        {
            printf ("0\n");
            continue;
        }
        LL phi = euler ( p );
        LL fb = index (n-2,phi) , fa = index ( n-3,phi );
        LL ans = pow ( b , fb , p )* pow ( a , fa , p ) %p ;
        printf ( "%I64d\n" , ans );
     }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值