数学递推(考查矩阵二分快速幂取模)
参考:http://www.cnblogs.com/staginner/archive/2011/12/14/2288187.html
输入n和M,简单来说就是要求f(n)%M,而f(n)=2*F(n)-1,F(n)为第n项费波那列数,所以问题转化为求F(n),由于n非常大n (0 <= n < 263-1)
所以线性递推会超时,要用矩阵快速幂的方法
初始化[F0,F1]=[0,1] , 要求[Fn,Fn+1]
[F0,F1] * |0 1| (n) = [Fn,Fn+1] (不考虑高精度)
|1 1|
用二分的方法求解|0 1| (n)
|1 1|
//初始化[f0,f1],要求[fn,fn+1] //[f0,f1] * |0 1| (n) = [fn,fn+1] (不考虑高精度) // |1 1| #include <cstdio> #include <cstring> #define MAX 550 long long b[MAX][2]; long long N,M; void pow_mod(long long n ,int c) { if(n==1) //递归边界,矩阵为0,1,1,1 { b[c][0]=0; b[c][1]=1; b[c+1][0]=1; b[c+1][1]=1; return ; } pow_mod(n/2,c+2); //递归,每次递归都产生一个矩阵,一个矩阵占两行所以c+2 long long A=b[c+2][0] , B=b[c+2][1] , C=b[c+3][0] , D=b[c+3][1]; b[c][0]= ( A*A+B*C )%M; b[c][1]= ( A*B+B*D )%M; b[c+1][0]=( C*A+D*C )%M; b[c+1][1]=( C*B+D*D )%M; if(n&1) //奇数还要乘上矩阵{0,1,1,1} { long long tmp; tmp=b[c][0]; b[c][0]=b[c][1]; b[c][1]+=tmp; tmp=b[c+1][0]; b[c+1][0]=b[c+1][1]; b[c+1][1]+=tmp; } //打印当前矩阵 // printf("\n| %lld %lld |\n",b[c][0],b[c][1]); // printf("| %lld %lld |\n",b[c+1][0],b[c+1][1]); return ; } void solve() { memset(b,0,sizeof(b)); //b用来保存递归过程中的矩阵,用空间换取时间 pow_mod(N,0); //矩阵二分快速幂取模 printf("%lld\n",(2*b[1][1]-1+M)%M); //可知F(n)就位于b[1][1]这个位置 } int main() { int T=0; while(scanf("%lld%lld",&N,&M)!=EOF) { if(!N && !M) break; printf("Case %d: %lld %lld ",++T,N,M); if(!N) printf("0\n"); //特判 else solve(); } return 0; }