我也是ACM初学者,最近为了准备校赛去做了好多工具题,比如说关于贪心问题,果园问题,大数阶乘,大数幂运算等等。现在就关于大数幂运算来探讨下怎么让你的算法又快又准!
原题来自:HDU2035(传送门:http://acm.hdu.edu.cn/showproblem.php?pid=2035);
说明:A^B的含义是“A的B次方”
10000^10000次怎么想也是超过了long的存储范围,所以暴力运算pow(10000,10000)求解是根本不行的!而且这道题目的时间限制也是在1S秒,如果你暴力求解时间复杂度O(n*n),n=10000的时候也肯定是超时的!
为了解决溢出问题,我们不能再完全计算后取摸,我们可以在a^b可以看成a*a*a.......(b个a相乘),我们可以在每两个a相成之后取模,那么第一次我们就可以分成(如果b一直都是偶数)b/2组a*a%1000,然后把每组a*a%1000的值赋值给a,b= b/2;这样在我们有面对的就是a^b模型了。一直迭代下去一直到b==1为止!输出b==1的时候a的值就是所要的结果!这样又解决了时间超时的问题,这种算法的时间复杂度为O(log2(n));
刚才我们假设的是b一直是偶数的情况,当时这种情况是极少发生的(当且仅当a = 2^n的时候成立)这个时候我们需要考虑如果b%2 != 0的情况也就是说b是奇数,这说明了在某次运算时候这些a*a*a...必定存在一个落单的a。尽管它是落单的,但是它也在影响着最后的结果。为了解决这个问题,我们可以定义一个变量用来收集所有在计算过程中落单的a;这里我初始化int left = 1;每次有落单的a,left = left *a%1000;这样我们就收集了所有落单的a;
好了分析到这里我们用代码说话吧!
#include<iostream>
using namespace std;
int main(){
int A,B;
while(cin>>A>>B){
int left=1;
int result;
if(A == 0)break;
while(B!=2&&B!=1){
if(B%2==1){
B--;
left = left*A%1000;
A = A*A%1000;
B = B/2;
}else{
A = A*A%1000;
B = B/2;
}
}
if(B==2){
result = A*A%1000;
result = result*left%1000;
}else{
result = A*left%1000;
}
cout<<result<<endl;
}
return 0;
}