首先这道题考的是递归调用的计数问题
最终返回时分别是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 );
}
}