目录
来自实训十 选做题
第六关 快速求幂
任务描述
本关任务:利用快速幂算法实现函数long long quickPow(int n, int k), 计算原理如下,其中int(x)表示不超过x的最大整数:
当k为偶数时, nk=(nk/2)2
当k为奇数时, nk=n(nint(k/2))2
编程要求
根据提示,在右侧编辑器补充代码,输入非负整数n和k,输出n的k次方
测试说明
平台会对你编写的代码进行测试:
测试输入:2 3
预期输出: 8
基础知识
1. int()是将向下取整的函数。
2. 偶数在二进制里面,最后一位为0,奇数则为1。 所以可以通过与1做 位与运算 判断奇偶数。 (num & 1) == 0 如果结果为true则为偶数,为false则为奇数。(num & 1)如果结果为true则为奇数,为false则为偶数。
3. 在c++中有双目移位运算符:<<(左移)和 >>(右移)。 移位运算符组成的 表达式 也属于 算术表达式 ,其值为算术值。语法格式:需要移位的数字>>移位的次数n
无符号:左移运算按二进制形式把所有数字向左移动相应的n位数,高位舍弃,低位的空位补0,相当于乘以2的n次方。比如8的二进制表示是00000000 00000000 00000000 00001000,左移2位(8<<2) 得到00000000 00000000 00000000 00100000,转换为十进制是。右移运算按二进制形式把所有数字向右移动相应的n位数,低位舍弃,高位的空位补0,相当于除以2的n次方。比如8的二进制表示是00000000 00000000 00000000 00001000,右移2位(8>>2) 得到00000000 00000000 00000000 00000010,转换为十进制是。
有符号:如果左移有符号的数字,以至于符号位受影响,则结果是不确定的。右移按二进制形式把所有数字向右移动相应的位数,低位舍弃,正数高位的空位补0;负数高位的空位补1。
原理
假设要求,如果,那么:。
这样只要做k次平方运算就能解决,时间复杂度就从O(n)下降到log(n)。
只要幂运算的幂可以写成包含的形式,就可以用上面的方法降低时间复杂度,所以我们可以将任意的实数n改写有限个2^k的形式的相加。比如,可以分别对和以及使用上述方法快速计算结果,最后三者相乘就可以了;比如,可以对和使用上述方法快速计算结果,两者相乘再乘以就可以了。
实现
1. 递归
#include <iostream>
#include <cmath>
using namespace std;
long long quickPow(long long a,long long b){
//特殊条件
if (a==1) return 1;
//递归
if (b==0) return 1;
if (b%2==1) return a * pow(quickPow(a, int(b/2)), 2);
if (b%2==0) return pow(quickPow(a, b/2),2);
}
int main()
{
int n, k;
cin >> n >> k;
cout << quickPow(n, k);
return 0;
}
2. 循环
可读性较强的版本
#include <iostream>
#include <cmath>
using namespace std;
long long quickPow(long long a,long long b){
long long res = 1;
while (b>0) {
//如果指数是偶数
if (b % 2 == 0) {
b /= 2;
a = a*a;
}
//如果指数是奇数
else {
b--; //使得b变成偶数,加上后面b /= 2达到向下取整的目的
res *= a;
b /= 2;
a = a*a;
}
}
return res;
}
int main()
{
int n, k;
cin >> n >> k;
cout << quickPow(n, k);
return 0;
}
较简洁的版本
#include <iostream>
#include <cmath>
using namespace std;
long long quickPow(long long a,long long b){
long long res = 1;
while (b) {
if (b & 1) res *= a;
a = a*a;
b >>= 1;
}
return res;
}
int main()
{
int n, k;
cin >> n >> k;
cout << quickPow(n, k);
return 0;
}