解题思路:
本题属于经典的递归题目,按照题意进行递归调用就能得到答案,但是需要注意一些细节。
注意事项:
1.注意矩阵相乘的写法(需要借助中间变量),否则会使得结果错误。
2.注意递归的使用范围(按照题目描述进行递归即可),在不该递归的地方进行递归使得程序进入死循环,最终时间超限。 若b=0,则A^b%m=I%m。其中I表示单位矩阵。
若b为偶数,则A^b%m=(A^(b/2)%m)^2%m,即先把A乘b/2次方对m求余,然后再平方后对m求余。
若b为奇数,则A^b%m=(A^(b-1)%m)*a%m,即先求A乘b-1次方对m求余,然后再乘A后对m求余。 题中加粗下划线部分提示了使用递归的情况,本人在解题时误认为将加粗下划线部分视为整体后等式右端也可采用递归,实则不然(错误代码见代码注释),因为这样会使已经通过递归减小的幂再次增大,导致递归无法结束,出现时间超限的情况。其实题中斜体加框部分已经说明了正确处理方法,所以大家在解题时一定要仔细读题。 参考代码:
#includevoid JZmod(int A[],int m){ for(int i = 0; i < 4; i++){ A[i] %= m; } } void JZProduct(int A[],int B[]){ int tem[4];//要用临时变量存储相乘结果 tem[0] = A[0] * B[0] + A[1] * B[2];//A[0] = A[0] * B[0] + A[1] * B[2];错误写法,改变了进行相乘的矩阵A tem[1] = A[0] * B[1] + A[1] * B[3]; tem[2] = A[2] * B[0] + A[3] * B[2]; tem[3] = A[2] * B[1] + A[3] * B[3]; //相乘后再对A重新赋值,边计算边赋值就不再是原来的矩阵相乘(例如计算A[1]时会用到A[0]) for(int i = 0; i < 4; i++){ A[i] = tem[i]; } } void quyu(int A[],int b,int m){ if(b == 0){ A[0] = 1, A[1] = 0, A[2] = 0, A[3] = 1; JZmod(A,m); return; } if(b % 2 == 0){ quyu(A,b/2,m); JZProduct(A,A); JZmod(A,m); //quyu(A,2,m);错误写法,递归无法结束(幂在1和2间交替),时间超限 } else { int a[4]; for(int i = 0; i < 4; i++){ a[i] = A[i]; } quyu(A,b-1,m); JZProduct(A,a); JZmod(A,m); //quyu(A,1,m);错误写法,递归无法结束(幂在1和0间交替),时间超限 } } int main(){ int b,m; scanf("%d%d",&b,&m); int A[4]; for(int i = 0; i < 4; i++){ scanf("%d",&A[i]); } quyu(A,b,m); printf("%d %d\n%d %d\n",A[0],A[1],A[2],A[3]); }
0.0分
1 人评分