问题描述
本文主要给出快速幂以及快速幂结合求模操作的一般方法
思路
当幂的数字太大时,计算的次数较大。
需要简化计算,可以采用快速幂。
二分幂的办法。
下面这是一种思路:
当b较大时,将其进行分解。
1. b为偶数时,a^b = a^(b/2) * a^(b/2)
2. b为奇数时,a^b = a^(b/2) * a^(b/2) * a
可用递归实现。
如果用非递归可在递归的基础上进行修改。但是要小心奇数和偶数的区别。
所以,还是要借助一个栈来实现。效率并不高。
下面讲另外一种思路:
主要思路是:
将a^b分解为若干个a^(2^k)项的乘积,也体现了分治的思想。
具体来说是在指数层面,将b分解为若干项(2^k)的和。
比如下面的例子:
3 ^ 999 = (3 ^ 512) * (3 ^ 256) * (3 ^ 128) * (3 ^ 64) * (3 ^ 32) * (3 ^ 4) * (3 ^ 2) * 3
= 3 ^ (512 + 256 + 128 + 64 + 32 + 4 + 2 + 1)
对于指数b的分解本质是求b的二进制形式
之所以写成二进制形式的好处是,前一位都可以由后一位的乘积构成。注意这里已经不是在指数层面了。
怎么判断哪一位的权出现,就看分解后相应二进制位是否有效。
看下面的问题: [ jobdu-1441]
题目描述:
求A^B的最后三位数表示的整数。说明:A^B的含义是“A的B次方”
输入:
输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B<=10000),如果A=0, B=0,则表示输入数据的结束,不做处理。
输出:
对于每个测试实例,请输出A^B的最后三位表示的整数,每个输出占一行。
样例输入:
2 3
12 6
6789 10000
0 0
样例输出:
8
984
1
方法一
int fast_pow( int a, int b, int mod )
{
if(1==b)
return a%mod;
else
{
int t = fast_pow( a, b/2, mod );
if( b%2 )
return ((t%mod)*(t%mod)*(a%mod))%mod;
else
return ((t%mod)*(t%mod))%mod;
}
}
int fast_pow_without_recursion( int a, int b, int mod )
{
std::stack<int> stk;
while( b > 1 )
{
stk.push(b%2);
b /= 2;
}
int ans = a%mod;
while( !stk.empty() )
{
int t = stk.top();
stk.pop();
if(t%2)
ans = (ans%mod * ans%mod * a%mod)%mod;
else
ans = (ans%mod * ans%mod)%mod ;
}
return ans;
}
方法二
int fast_pow1( int a, int b, int mod )
{
int ans = 1;
int w = a;
while( b )
{
if(b%2)
ans = (ans * w%mod)%mod;
w *= w;
b /= 2;
}
return ans;
}
这个方法,看起来逻辑并没有问题。但是在调试的时候最后一组数据没有过。
1. 边界数据的问题
2. 中间值w*w过大
仔细分析后发现,由于每一个中间项都是由前一项平方得来。所以,加载这一项的求mod。
可以移到前面去。并且,最后一组数据爆了的原因就是,a很大之后w*w很容易直接爆掉。
所以,把求mod放在这里是正确的。应该可以解决之前的问题。
int fast_pow2( int a, int b, int mod )
{
int ans = 1;
int w = a;
while( b )
{
if(b%2)
ans = (ans * w)%mod;
w = (w%mod * w%mod)%mod;
b /= 2;
}
return ans;
}
总结
刷题一定要有耐心,就像对于方法二。满怀信心,觉得逻辑没有任何错误。但是还是有问题。不能直接百度,一定要自己反复思考,别害怕浪费时间。出来混的早晚都是要还的。虽然最后一点想了好久,但是最后还是想出来了,现在看来也许是轻而易举的事,但是你没到那个程度肯定是不行的。有问题是好事,有问题就能提高。享受解决问题的过程,这就是游戏,看你怎么玩。