本题暴力解的话会超时。所应用的方法是快速幂,其主要思想是这样的:比如求3^7
3^1 = 3;
3^2 = 9;
3^3 = 27;
这里的3^3不是暴力算出来的,我们已经算出来了3^1 = 3和3^2 = 9;所以两者相乘就是3^3。所以快速幂之所以快就是因为,它利用了前面的结果,避免了重复计算。下面我们需要考虑,怎么样才能让计算机知道现在要用前面的那些结果呢?我们以3^5为例讲解,现在假设已经计算到3^5了,那么我么该用前面的哪些结果呢?
3^1 = 3;
3^2 = 9;
3^3 = 27;
3^4 = 81;
3^5 = 243;
我们既可以用3^1 * 3^4 = 81得到,也可以用3^2 * 3^3得到。而我们必须给计算机确定的指令。我们不妨把指数5分解,5 = 2^0 + 2^2.当然,你也可以分解为其他底我们之所以以2为底是考虑到计算机二进制的特性,可以天然的减少分解操作。5对应的二进制形式为101,不难发现,二进制数制的表示上就是将有效位置为1.从5的二进制里可看出0和2位是有效位,正好满足分解等式。 因此,我们只需把所有有效位相乘就可以得到结果。
#include<iostream>
using namespace std;
int main() {
int a, b, p;
cin >> a >> b >> p;
int res = 1;
while (b) {
if (b & 1) res = res * 1ll * a%p;//b & 1取当前位,1ll强制转化为long long类型。
a = a * 1ll * a%p;
b >>= 1;
}
cout << res << endl;
return 0;
}
下面来一道练习题:
不难发现,该题也是应用快速幂的思想,找有效位,快速幂是将有效位相乘,而快速和则是将有效位相加。
#include<iostream>
using namespace std;
typedef unsigned long long ULL;
int main() {
ULL a, b, p;
cin >> a >> b >> p;
ULL res = 0;
while (b) {
if (b & 1) res = (res + a) % p;
a = a * 2 % p;
b >>= 1;
}
cout << res;
return 0;
}