乘方快速幂
乘方快速幂,是为了解决a^b次方普通计算方法太慢的问题。
计算a的b次方,普通的for循环求法如下(O(n)):
1 int a(int x,int n) 2 { 3 int t=1; 4 for(int i=1;i<=n;i++) 5 { 6 t=t*x; 7 } 8 return t; 9 }
递归求法:
1 int Pow(int a,int b) 2 { 3 if(b==0) 4 return 1; 5 else 6 return Pow(a,b-1)*a; 7 }
二分(递归)求法:
1 int pow(int a,int b) 2 { 3 if(b==0) 4 return 1; 5 if(b%2==0) 6 return pow(a*a,b/2); 7 return a*pow(a*a,b/2); 8 }
当然,数学函数pow(a,b)一步解决问题。但是,因为对时间的要求,有些算法往往时间效率不高,而乘方快速幂也是(O(logn))的解法。
首先,3的26次方,我们可以发现它完全不需要一次一次的乘,因为26次方==2^1+2^3+2^4=2+8+16
所以3^26 = 3^2 *3^8 * 3^16,而3^2=(3^1)^2,(3^4)=(3^2)^2,3^8=(3^4)^2,所以O(logn)的时间可求出3^2,
3^4,3^8...当然,如果指数很大的话,我们不好一点一点分析如何差解,所以我们拿指数的二进制入手。
如26的二进制表示为11010,1对应的权值为16,8,2。它们表示的含义即为对应的乘方次幂是需要的。当然这种分发不唯一的,你也可以分成8,8,4,4,2。但是为了计算方便和应对指数幂很大的情况,根据二进制位是1来划分是最高效的。
对应的算法如下:
1 long long Quick_Pow(long long a,long long b) 2 { 3 long long ans = 1; 4 while(b)//指数不为0 5 { 6 if(b & 1)//b为奇数,即二进制最右边一位为1时,说明需要乘这个数 7 ans = ans * a ; 8 a = a*a ;//否则底数自乘积 9 b >>= 1;//右移1位 10 } 11 return ans; 12 }
可以简单检验运行结果。
当然,当结果很大的时候,或要求对答案进行取模处理,这只需要在代码中简单处理即可。
1 long long Quick_Pow(long long a,long long b,long long mod) 2 { 3 long long ans = 1; 4 while(b) 5 { 6 if(b & 1) 7 ans = ans * a % mod ; 8 a = a*a % mod ; 9 b >>= 1; 10 } 11 return ans; 12 }
题目链接:
Raising Modulo Numbers 、 Pseudoprime numbers P3414 SAC#1 - 组合数
----------------------------------------------------------------------------------------------------------------转载请说明出处----------------------------------------------------------------------------------------------------------------------
你要做一个不动声色的大人了。不准情绪化,不准偷偷想念,不准回头看。去过自己另外的生活。你要听话,不是所有的鱼都会生活在同一片海里。
————————村上春树