问题介绍:给一个整数n,找到最小的x(x > 0),使满足 2 ^ x mod n = 1
问题解析:对于a * b % c 有公式: a * b % c = ((a % c) * (b % c)) % c.
所以可以通过递归求解a ^ b mod c.穷举x,便可写出以下代码:
1 #include<stdio.h> 2 #include<iostream> 3 using namespace std; 4 5 //a ^ b % c 6 int get_mod(__int64 a, int b, int c) 7 { 8 if(b == 1) 9 return a % c; 10 return get_mod(a, b - 1, c) * a % c; 11 //((a ^ (b - 1) % c) * a) % c 12 } 13 14 15 int main() 16 { 17 int n; 18 while(cin>>n) 19 { 20 if(n % 2 == 0 || n <= 1) 21 printf("2^? mod %d = 1 ", n); 22 else 23 { 24 int x; 25 for(x = 1; ; x++) 26 if(get_mod(2, x, n) == 1) 27 { 28 printf("2^%d mod %d = 1 ", x, n); 29 break; 30 } 31 } 32 } 33 return 0; 34 } 35
显然,当n比较大时,上述算法的效率很低,最终导致超时...需要修改莫幂运算的算法.
需要使用一种数学方法:蒙哥马利幂模运算(是快速计算a^b%k的一种算法).
由于a * a % c = ((a % c) * (a % c)) % c = ((a % c)^2) % c. 可以将两次运算转换为一次乘方运算.
所以可以通过这样的递归公式:a ^ 2n % c = (a ^ n % c) ^ 2 % c.可以二分计算.
效率由原来的n变为log2(n).当n很大时,效率提升数万倍.
注意,当n为奇数时,需要利用正常的递推方法使n - 1为偶数带入下一次计算.
修改后的代码:
1 //给一个整数n,找到最小的x(x > 0),使满足 2 ^ x mod n = 1 2 3 #include<stdio.h> 4 #include<math.h> 5 #include<iostream> 6 using namespace std; 7 8 //a ^ b % c 9 int get_mod(__int64 a, int b, int c) 10 { 11 if(b == 1) 12 return a % c; 13 if(b % 2 == 1) 14 return (get_mod(a, b - 1, c) * (a % c)) % c; 15 return (int)pow(get_mod(a, b / 2, c), 2) % c; 16 //((a ^ (b - 1) % c) * a) % c 17 } 18 19 20 int main() 21 { 22 int n; 23 while(cin>>n) 24 { 25 if(n % 2 == 0 || n <= 1) 26 printf("2^? mod %d = 1 ", n); 27 else 28 { 29 int x; 30 for(x = 1; ; x++) 31 if(get_mod(2, x, n) == 1) 32 { 33 printf("2^%d mod %d = 1 ", x, n); 34 break; 35 } 36 } 37 } 38 return 0; 39 } 40