快速幂求a的b次方%m
题目网址:http://class.51nod.com/Challenge/Problem.html#problemId=1046
前言
当我知道快速幂之后。才发现 a ^ b还能这样算。数学之美就是你在能不断刷新你的认知。
快速幂的递归写法
我们已知 23 求 26,不就是 23 * 23嘛。快速幂的递归写法就是这个原理。
那有同学问了遇到奇数怎么办?25??
那不就是 2 * 24 这不就成了嘛。
所以这就是快速幂的基本思路求ab
1)当b是奇数时,那么有 a^b = a * a^(b-1)
2)当b是偶数时,那么有 a^b = a^(b/2) * a^(b/2)
举个例子?210
210 | = | 25 * 25 |
25 | = | 2 * 24 |
24 | = | 22 * 22 |
22 | = | 21 * 21 |
21 | = | 2 * 20 |
根据这两个条件写递归式嘛,这还不简单?
#include<cstdio> #include<iostream> using namespace std; long long quick_pow(long long a, long long b, long long m){//求a的b次方 if(b == 0){ return 1; }else if(b % 2 == 1){ return ((a % m) * (quick_pow(a, b-1, m) % m)) % m; }else{ return ((quick_pow(a, b/2, m) % m) * (quick_pow(a, b/2, m) % m)) % m; } } int main(){ long long a, b, c, ans = 1, cur = a; cin >> a >> b >> c; cout << quick_pow(a, b, c); return 0; }
针对不同的题目,有两个细节需要注意
1)如果初始值a 大于 m ,那么需要在进入函数前就让a 对 m 取模,
2)若果m 为 1,可以直接在函数外部特判为 0,不需要进入函数来计算。(因为任何数对1 取模都是0)
快速幂的迭代写法
a的b次方中a是底数平方这样上去的(2 4 16 256……),b是幂乘二*2上去的(2、4、8、16、32……)
x(2^29) | …… | x4 | x2 | x1 |
可以把109这么多次循环相乘转换成二进制的29位数字。109次方是怎么变成29位的二进制数呢?
1、log以2为底的109
2、9个log以2为底的10
3、9个log以2为底的10 -> 10是2的3.3次方
4、9*3.3大约等于29
5、29位
现在我们已经知道有多少位了,接下来可以通过前缀积的方式求出二进制每个位置上x是几次方。
对于 a ^ b来说,若果把 b 写成2 进制,那么b 就可以写成若干二次幂之和,如13 的二进制 1101,于是3 号位 、2号位、0号位就都是1,那么就可以得到13 = 2^3 + 2^2 + 2^1 = 8 + 4 + 1。所以a 13 = a8 * a4 * a1。
通过同样的推导,我们可以把任意的a^b 表示成 a2^k……、a8、a4、a2、a1中若干的乘积。若果二进制的i号位为1.那么想中的a(2^i)就被选中。于是可以得到计算a^b的大致思路:令i 从0到k枚举b的二进制的每一位,如果为1 那就累计a(2^i)。注意a(2^k)……、a8、a4、a2、a1前一项总是等于后一项的平方。具体步骤如下。
(1)初始ans = 1,用来存放累积的结果
(2)判断b的二进制末尾是否为1 ,(及判断 b&1 是否为 1)如果是的话,ans乘上a的值
(3)a赋值为a平方,每往左边移动一位就要求一次平方。这样如果二进制位上是1的话就可以直接乘上a了。
(4)b=b/2,表示要求下一个位置的值是不是1了
(5)如果b<0了返回ans的值。
例:a13
b | b&1 | ans | a |
1 | a | ||
1101 | 1 | 1*a=a | a2 |
110 | 0 | a | a4 |
11 | 1 | a*a4 = a5 | a8 |
1 | 1 | a5 * a8 = a13 |
迭代代码:
#include<cstdio> #include<iostream> using namespace std; long long quick_pow(long long a, long long b, long long m){ long long ans = 1; while(b > 0){ if(b & 1){ ans = ans * a % m; } a = a * a % m;//每一个位置都要乘一次平方,底数平方 b >>= 1;//判断下一个位置了,幂乘二 } return ans;//返回累积的结果 } int main(){ int a,b,c; cin >> a >> b >> c; cout << quick_pow(a,b,c); return 0; }