快速幂
通常地,我们计算 a x a^x ax是将 x x x从1一直累乘到 x x x,这样是最简单的计算方法,但是这种做法的时间复杂度是 o ( n ) o(n) o(n),一旦我们计算的幂次方较大或者计算次数较多的时候就会花费很长的时间;例如:计算 1 0 100000000 10^{100000000} 10100000000组类似 99 9 100000000 999^{100000000} 999100000000这样的计算式,你可能算一辈子都算不出来。
这个时候引入二进制对 a x a^x ax进行优化:
考虑 a 2 x a^{2x} a2x= a x × a x a^x×a^x ax×ax= ( a x ) (a^x) (ax) 2 ^2 2于是可以利用二进制表示分割成更小的一部分
例如: 9 13 9^{13} 913= 9 ( 1101 ) 2 9^{(1101)_2} 9(1101)2= 9 8 9^8 98× 9 4 9^4 94× 9 1 9^1 91
因为 n n n有 [ l o g 2 x ] + 1 [log_2x]+1 [log2x]+1个二进制位,因此当我们知道了 a 1 , a 2 , a 4 . . . a 2 k a^1,a^2,a^4...a^{2^k} a1,a2,a4...a2k后,我们只用计算 [ l o g 2 x ] + 1 [log_2x]+1 [log2x]+1次乘法就可以计算出 a x a^x ax
因此计算 a x a^x ax只需要将 x x x对应的二进制下的数位为1的整系数幂乘起来即可
即: a x a^x ax= a ( x 0 x 1 x 2 . . x n ) 2 a^{(x_0x_1x_2..x_n)_2} a(x0x1x2..xn)2= a x 0 2 0 a^{x_02^{0}} ax020× a x 1 2 1 a^{x_12^{1}} ax121× a x 2 2 2 a^{x_22^{2}} ax222…× a x n 2 n a^{x_n2^{n}} axn2n
根据上式发现,原问题被转化成了形式相同的子问题的乘积,并且我们可以在常数时间内从 2 i 2^i 2i 项推出 2 i + 1 2^{i+1} 2i+1项。
通过二进制处理后时间复杂度降为 O ( l o g n ) O(logn) O(logn)
下面是我的快速幂代码模版:
long long fastpow(long long a, long long n) //快速幂
{
long long ans = 1;
while (n)
{
if (n & 1)
{
ans *= a;
}
a *= a;
n >>= 1; //位运算
}
return ans;
}