王道机试练习——巧妙求A^B(A的B次幂)二分求幂法
题目描述
求 A^B 的最后三位数表示的整数。说明: A^B 的含义是 ―A的 B 次方
输入: 输入数据包含多个测试实例,每个实例占一行,由两个正整数 A 和 B 组成 (1<=A,B<=10000),如果 A=0, B=0,则表示输入数据的结束,不做处理。
输出: 对于每个测试实例,请输出 A^B 的最后三位表示的整数,每个输出占一行。
样例输入:
23
12 6
6789 10000
00
样例输出:
8
984
1
二分求幂法
我们的目标即分解 a 的 b 次变为若干个 a 的 2^k 次
的积,并尽可能减少分解结果的个数。在指数层面即分解 b 为若干个 2^k 的和, 并尽可能减少分解结果的个数。若读者认真完成了本章之前的内容,就应该能联 想到分解 b 为若干个 2^k 的和且分解个数最小,这便是求 b 的二进制数。在求得 b 的二进制数后,各个二进制位为 1 的数位所代表的权重即是分解的结果。以 2 的 31 次方为例,我们首先求得 31 的二进制数 11111,在二进制表达式中 31 即被 表达成 (11111) = 2^0 + 2^1 + 2^2 + 2^3 + 2^4,这就是我们所需的分解结果。即拆 2 的 31 次为 2 的 0 次、1 次、2 次、3 次、4 次的乘积,即得到前文中所讲的结 果。 所以,二分求幂对要求的次数并没有特殊的要求,而是对任何要求的次数都 可以采用二分求幂来大大减少其乘法运算的次数。
解题原理
那么在本例中,我们先求得 A^B 的具体数字再求其后 三位数么?这毫无疑问是不可行的,按照题面给明的输入规模, A^B 的次至多 可以达到 10000 的 10000 次,这么庞大的数字是非常不容易保存的,但是我们应
该注意到 A^B 的后三位数只与 A 的后三位数和 B 有关。这样,由于要求的仅是 最后结果的后三位数,那么我们在保存为计算该最终值的中间值时也只需保存其 后三位数即可。即,计算过程中的所有中间结果我们仅保存和使用其后三位数。 那么,我们再利用二分求幂来求得 A^B 次,同时在计算中间结果时我们都仅保 存后三位数。这样 ,我们就不用担心数字不能被保存的问题了 。
代码
#include<iostream>
using namespace std;
int main() {
int a, b;
while (cin >> a >> b) {
if (a == 0 && b == 0) break;
int ans = 1;//保存最终变量,初始值为1
while (b != 0) {//若b不等于0,即对b转换2进制过程未结束
if (b % 2 == 1) {//若当前二进制位为1,则需要累成a的2^k次至变量ans
//其中2^k为当前二进制位的权重
ans *= a;//最终结果累乘a
ans %= 1000;//求其后三位数
}
b /= 2;//b除以2
a *= a;//求下一位二进制位的权重,a求其平方,即从a的1次开始,依次求a的2次,a的4次……
a %= 1000;//求a的后三位
}//一边计算b的二进制,一边计算a的2^k次,并将需要的部分乘到变量ans上
cout << ans;//输出
}
return 0;
}