[Problem]
Calculate the value of a ** B % C.
"**" Indicates the power (which is expressed in Python); "%" indicates the modulo operation.
[Analysis]
First, the following formula is obtained based on the nature of the modulo operation:
(A * B) % C = (a % C) * B % C [Formula 1]
Expand Formula 1. The following formula is available:
(A * B) % C = (a % C) * B % C = (B % C) * (a % C) % C = (a % C) * (B % C) % C [formula 2]
Below are several solutions:
Method 1: Use Formula 1 and recursive calculation.
# Include <cstdio> <br/> # include <cassert> <br/> // calculate a ** B % C <br/> int fun (int A, int B, int c) <br/>{< br/> assert (A & (B> = 0) & C); <br/> If (0 = B) <br/>{< br/> return 1; <br/>}< br/> else <br/> {<br/> return fun (A, B-1, c) * A % C; <br/>}< br/> int main () <br/>{< br/> int A, B, C; <br/> while (3 = scanf ("% d", & A, & B, & C )) <br/>{< br/> printf ("% d/N", fun (a, B, c )); // calculate a ** B % C <br/>}< br/> return 0; <br/>}
The disadvantage of this method is that the larger the value of B, the more recursion is required. Therefore, the stack overflow error may occur. Therefore, this method is very simple but only applicable when B is small. Stack Overflow occurs when recursion reaches 4624 times in vs2008.
Method 2]
Use formula 2 and recursive calculation.
Try to reduce the number of recursion on the basis of method 1, and find that formula 2 can be used.
(A * B) % C = (a % C) * (B % C) % C [formula 2]
When B is odd, F (B) = f (b-1) * (a % C) % C = A * F (b-1) % C
When B is an even number, F (B) = f (B/2) * F (B/2) % C
# Include <cstdio> <br/> # include <ctime> <br/> # include <cassert> <br/> // calculate a ** B % C <br/> int fun (int, int B, int c) <br/>{< br/> assert (A & (B> = 0) & C ); <br/> If (0 = B) <br/>{< br/> return 1; <br/>}< br/> else <br/> {<br/> return (1 = (B & 1 ))? A * Fun (A, B-1, c) % C: Fun (A, B/2, c) * Fun (A, B/2, c) % C; <br/>}< br/> int main () <br/>{< br/> int A, B, C; <br/> clock_t beg, end; <br/> while (3 = scanf ("% d", & A, & B, & C )) <br/>{< br/> beg = clock (); <br/> printf ("% d/N", fun (a, B, c )); // calculate a ** B % C <br/> end = clock (); <br/> printf ("time used: %. 2lf/N ", double (end-Beg)/clocks_per_sec); <br/>}< br/> return 0; <br/>}
Vs2008 test: A = 3; B = 2147483647; (take the maximum value of the int type) C = 1000, about 787 s is required to calculate the result.
This method reduces the number of recursion times and prevents stack overflow in the types that can be expressed (which can be inferred below). However, it is found that the operation efficiency is still too slow, check the code to find that the problem lies in the following line of code:
Fun (A, B/2, c) * Fun (A, B/2, c) % C;
This write method may lead to 2 * lb (B) Number of recursive function calls. Although the recursive depth is much smaller than method 1, however, the number of recursion times is much greater than method 1 (you can set a local static variable display), so the efficiency is very low. You can use a temporary variable to save the return value of the function call. The optimization method is as follows:
# Include <cstdio> <br/> # include <ctime> <br/> # include <cassert> <br/> // calculate a ** B % C <br/> int fun (int, int B, int c) <br/>{< br/> assert (A & (B> = 0) & C ); <br/> If (0 = B) <br/>{< br/> return 1; <br/>}< br/> else <br/> {<br/> // return (1 = (B & 1 ))? A * Fun (A, B-1, c) % C: Fun (A, B/2, c) * Fun (A, B/2, c) % C; <br/> If (B & 1) // odd <br/> {<br/> return a * Fun (A, B-1, c) % C; <br/>}< br/> else // even <br/> {<br/> int TMP = fun (A, B/2, c ); // note here! <Br/> return TMP * TMP % C; <br/>}< br/> int main () <br/>{< br/> int A, B, C; <br/> clock_t beg, end; <br/> while (3 = scanf ("% d", & A, & B, & C )) <br/>{< br/> beg = clock (); <br/> printf ("% d/N", fun (a, B, c )); // calculate a ** B % C <br/> end = clock (); <br/> printf ("time used: %. 2lf/N ", double (end-Beg)/clocks_per_sec); <br/>}< br/> return 0; <br/>}< br/>
Using the same data test above, it is found that the calculation time is almost 0.00 S, and the efficiency is greatly improved.
Thinking: although this method reduces the number of recursion times, whether stack overflow occurs when B is very large.
Test: Change B to _ int64 or long to see if Stack Overflow occurs and calculate the time.
It can be roughly analyzed: using this method on a 32-bit platform, we can calculate the result of a maximum of 2 ^ 4624 B without stack overflow.
# Include <cstdio> <br/> # include <ctime> <br/> # include <cassert> <br/> // calculate a ** B % C <br/> int fun (int, _ int64 B, int c) <br/>{< br/> assert (A & (B> = 0) & C ); <br/> // print the number of recursion Times <br/>/* Static int itime = 0; <br/> printf ("% d/N", itime ++ ); */<br/> If (0 = B) <br/>{< br/> return 1; <br/>}< br/> else <br/> {<br/> If (B & 1) // odd <br/>{< br/> return a * Fun (A, B-1, c) % C; <br/>}< br/> else // even <br/> {<br/> int TM P = fun (A, B/2, c); // note here! <Br/> return TMP * TMP % C; <br/>}< br/> int main () <br/>{< br/> int A, C; <br/>__ int64 B; <br/> clock_t beg, end; <br/> while (3 = scanf ("% d % i64d % d", & A, & B, & C )) <br/>{< br/> beg = clock (); <br/> printf ("% d/N", fun (a, B, c )); // calculate a ** B % C <br/> end = clock (); <br/> printf ("time used: %. 2lf/N ", double (end-Beg)/clocks_per_sec); <br/>}< br/> return 0; <br/>}< br/>
Test: A = 3; B = 9223372036854775807; C = 1000; the output is 187, and the time is almost 0.00 S.
[Method 3] Formula 1 is used for Recursive calculation.
# Include <cstdio> <br/> # include <ctime> <br/> # include <cassert> <br/> // calculate a ** B % C <br/> int fun (int, int B, int c) <br/>{< br/> assert (A & (B> = 0) & C); <br/> int res = 1; <br/> while (B> 0) <br/> {<br/> res * = A; <br/> res % = C; <br/> -- B; <br/>}< br/> return res; <br/>}< br/> int main () <br/>{< br/> int A, B, c; <br/> clock_t beg, end; <br/> while (3 = scanf ("% d", & A, & B, & C) <br/>{< br/> beg = clock (); <br/> printf ("% d/N", fun (A, B, c); // calculate a ** B % C <br/> end = clock (); <br/> printf ("time used: %. 2lf/N ", double (end-Beg)/clocks_per_sec); <br/>}< br/> return 0; <br/>}< br/>
Test: When a = 3; B = 2147483647; (the maximum value of the int type) C = 1000, about 787 s can be used to calculate the result.
Because this method needs to be repeated for B times, the time complexity is O (B), and the efficiency is relatively low, but the advantage is that stack overflow will not occur.
[Method 4] formula 2 is used for Recursive calculation.
# Include <cstdio> <br/> # include <ctime> <br/> # include <cassert> <br/> // calculate a ** B % C <br/> int fun (int, int B, int c) <br/>{< br/> assert (A & (B> = 0) & C); <br/> int res = 1; <br/> while (B) <br/> {<br/> If (B & 1) // odd <br/>{< br/> res = res * A % C; <br/> -- B; <br/>}< br/> else // even <br/>{< br/> A = A * A % C; <br/> B >>= 1; <br/>}< br/> return res; <br/>}< br/> int main () <br/>{< br/> int A, B, C; <br/> clock_t beg, end; <br/> while (3 = scanf ("% d", & A, & B, & C )) <br/>{< br/> beg = clock (); <br/> printf ("% d/N", fun (a, B, c )); // calculate a ** B % C <br/> end = clock (); <br/> printf ("time used: %. 2lf/N ", double (end-Beg)/clocks_per_sec); <br/>}< br/> return 0; <br/>}
Test: A = 3; B = 2147483647; (take the maximum value of the int type) C = 1000, the result can be calculated as 787 in about S. The best time complexity of this method is O (lb (B) without stack overflow.
Method 5 is another form equivalent to Method 4.
If B is not subtracted from 1 or divided by 2, B is expressed as the binary number, which is calculated by determining whether the binary bit is 0 or 1. This method has the minimum time complexity, that is, O (nbit), where N is the number of bits in binary representation. For example:
B = 8 (dec .) = 1000 (bin .), method 4 requires 2 + 1 + 1 + 0 = 4 cycles; Method 3 also requires 4 cycles.
B = 7 (dec.) = 0111 (bin.), use method 4 to cycle 2 + 2 + 1 = 5 times; Use method 3 to loop 4 times.
Using Arrays
:
# Include <cstdio> <br/> # include <ctime> <br/> # include <cassert> <br/> // calculate a ** B % C <br/> int fun (int, int B, int c) <br/>{< br/> assert (A & (B> = 0) & C); <br/> int res = 1, n = 0; // n + 1 is the length of B in binary <br/> int bit_ B [32] = {0}; <br/> while (B) <br/>{< br/> bit_ B [n ++] = (B % 2); <br/> B >>= 1; <br/>}< br/> for (INT I = n-1; I> = 0; -- I) <br/>{< br/> res = res * res % C; <br/> If (bit_ B [I]) <br/>{< br/> res = res * A % C; <br/>}< br/> return res; <br/>}< br/> int main () <br/>{< br/> int A, B, C; <br/> clock_t beg, end; <br/> while (3 = scanf ("% d", & A, & B, & C )) <br/>{< br/> beg = clock (); <br/> printf ("% d/N", fun (a, B, c )); // calculate a ** B % C <br/> end = clock (); <br/> printf ("time used: %. 2lfs/N ", (double) (end-Beg)/clocks_per_sec); <br/>}< br/> return 0; <br/>}
Using bitset containers
:
# Include <cstdio> <br/> # include <cassert> <br/> # include <bitset> <br/> Using STD: bitset; <br/> // calculate a ** B % C <br/> int fun (int A, int B, int C) <br/>{< br/> assert (A & (B> = 0) & C); <br/> int res = 1, N; // n + 1 is the length of B in binary <br/> bitset <32> bitvec_ B (B); <br/> N = bitvec_ B .size ()-1; <br/> while (0 = bitvec_ B [N]) <br/> -- N; <br/> for (INT I = N; I> = 0; -- I) <br/>{< br/> res = res * res % C; <br/> If (bitvec_ B [I]) <br/>{< br/> res = res * A % C; <br/>}< br/> return res; <br/>}< br/> int main () <br/>{< br/> int A, B, C; <br/> while (3 = scanf ("% d", & A, & B, & C )) <br/>{< br/> printf ("% d/N", fun (a, B, c )); // calculate a ** B % C <br/>}< br/> return 0; <br/>}< br/>
Reference
:
[1] 2010.10.24 Baidu pen Test
[2] Introduction to The menggomery Algorithm
[3] Some algorithm questions