▶ 指数取模运算 ab % m
▶ 参考维基 https://en.wikipedia.org/wiki/Modular_exponentiation,给了几种计算方法:暴力计算法,保存中间结果法(分为左到右的二进制法和右到左的二进制法),矩阵法,优先群法,量子计算法。
● 代码,18 ms,令 a' = a % m,b = 10 * c + d(0 ≤ d < 10),则 ab % m == ((ac % m)10 % m) * (ad % m) % m,每次将指数的个位拆出来单独算,再和高位部分乘在一起。指数运算采用线性乘法,合并过程采用从右到左的二进制法,并使用了递归。
1 class Solution 2 { 3 const int mod = 1337; 4 int powMod(int a, int k) //a^k mod 1337 where 0 <= k <= 10 5 { 6 a %= mod; 7 int i, result; 8 for (i = 0, result = 1; i < k; result = (result * a) % mod, i++); 9 return result; 10 } 11 public: 12 int superPow(int a, vector<int>& b) 13 { 14 if (b.empty()) 15 return 1; 16 int last_digit = b.back(); 17 b.pop_back(); 18 return powMod(superPow(a, b), 10) * powMod(a, last_digit) % mod; 19 } 20 };
● 代码,10 ms,与上述算法相同,指数运算采用从右到左的二进制法,合并过程采用从左到左到右二进制法,并使用了递归。
1 class Solution 2 { 3 public: 4 const int mod = 1337; 5 int powMod(int a, int b)// a ^ b % mod 6 { 7 int result; 8 for (result = 1; b; b >>= 1) 9 { 10 if (b & 1) 11 result = (result * a) % mod; 12 a = (a * a) % mod; 13 } 14 return result; 15 } 16 int superPow(int a, vector<int>& b) 17 { 18 int i, result; 19 for (a %= mod, i = b.size() - 1, result = 1; i >= 0; i--) 20 { 21 if (i < b.size() - 1) 22 a = powMod(a, 10); 23 result = (result * powMod(a, b[i])) % mod; 24 } 25 return result; 26 } 27 };
● 代码,8 ms,注意到欧拉 - 费马定理,对于任意正整数 a 和 n 有 aφ(n) ≡ 1 (mod n),于是令 b = φ(m) * c + d(0 ≤ d < φ(n)),则 ab % m == ad % m,这里 φ(1337) = 1337 * ( 1 - 1 / 7 ) * ( 1 - 1 / 191 ) = 1140
1 class Solution 2 { 3 public: 4 const int mod = 1337; 5 int superPow(int a, vector<int>& b) 6 { 7 int p = 0, ret; 8 for (int i : b) 9 p = (p * 10 + i) % 1140; 10 if (p == 0) 11 p += 1140; 12 for (ret = 1, a %= mod; p > 0; a = a * a % mod, p >>= 1) 13 { 14 if (p & 1) 15 ret = ret * a % mod; 16 } 17 return ret; 18 } 19 };