题目描述
求 a 的 b 次方对 p 取模的值。
样例
输入
3 2 7
输出
2
解释
3^2 % 7 = 9 % 7 = 2
分析
按照朴素算法就是把 a a a连乘 b b b次,这样一来时间复杂度是 O ( b ) O(b) O(b)也即是 O ( n ) O(n) O(n)级别,快速幂能做到 O ( l o g n ) O(logn) O(logn)。
a b a^b ab,那么其实b是可以拆成二进制的,该二进制数第i位的权为 2 i − 1 2^{i−1} 2i−1,例如当 b = = 11 b==11 b==11时, a 11 = a ( 2 0 + 2 1 + 2 3 ) a^{11}=a^{(2^0+2^1+2^3)} a11=a(20+21+23)。
11 11 11的二进制是 1011 1011 1011, 11 = 2 3 × 1 + 2 2 × 0 + 2 1 × 1 + 2 0 × 1 11 = 2^3×1 + 2^2×0 + 2^1×1 + 2^0×1 11=23×1+22×0+21×1+20×1,因此,我们将 a 11 a^{11} a11转化为算 a 2 0 a 2 1 a 2 3 a^{2^0}a^{2^1}a^{2^3} a20a21a23 。
由于是二进制,很自然地想到用位运算这个强大的工具: & 和 > > >> >> ,&运算通常用于二进制取位操作,例如一个数 & 1 的结果就是取二进制的最末位。还可以判断奇偶x&1 = = 0 ==0 ==0为偶,x&1==1为奇。 > > >> >>运算比较单纯,二进制去掉最后一位 。
代码
#include <iostream>
using namespace std;
//快速幂
int main(){//把b拆成二进制表示
int a, b, p;
cin >> a >> b >> p;
int res = 1 % p;
while(b){
if(b&1) res = res * 1ll * a % p;
//对指数b进行二进制拆分,只有二进制位为1的位是有用的位
a = a * 1ll * a % p;
b >>= 1; //把b的二进制个位去掉
}
cout << res << endl;
return 0;
}