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