浅谈快速幂
求 \(a^b\),先上代码吧
int qsm(int a,int b){
int ans = 1,base = a;
while(b){
if(b&1) ans *= base;
base *= base;
b>>=1;
}
return ans;
}
以 \(a = 3, b = 21\) 为例
\(①\) \(:\) \(b >>= 1\) (位运算,就是除以2)是快速幂加速的关键, 它将线性的时间复杂度 \(b\) 降为 \(log_2b\),效果体现就是去掉尾数后各位数往低位移一位.如\(10101\) (\(21\)) 变为 \(1010\) (\(10\)).
\(②\) \(:\) \(base = base \times base\),这一步是配合 \(①\) 不断积累 \(base\).(\(base = a^1,a^2,a^4\),\(a^8\),\(a^{16}\)......)
\(③\) \(:\) \(b\)&\(1\)则是判断尾位是否为\(1\),是\(1\)就将\(②\)中累积\(base\)乘上.
解释例子:
\(①\) \(b = 10101\),尾数为\(1\),\(ans\) 乘上 \(base\) 为 \(3^1\),\(b\) 变为 \(1010\) ,\(base\) 积累为 \(3^2 = 4\).
\(②\) \(b = 1010\),尾数为\(0\),\(b\) 变为了 \(101\), \(base\) 积累为 \(3^2 \times 3^2 = 3^4\).
\(③\) \(b = 101\),尾数为\(1\), \(ans\) 乘上 \(base\) 为 \(3^1 \times 3^4\), \(b\) 变为\(10\), \(base\)积累为 \(3^{8}\).
\(④\) \(b = 10\),尾数为\(0\), \(b\)变为\(1\),\(base\)积累为 \(3^{16}\).
\(⑤\) \(b = 1\), 尾数为\(1\),\(ans\) 乘上 \(base\) 为\(3^1 \times 3^4 \times 3^{16}\), \(b\)变为了\(0\), \(base\)积累为 \(3^{32}\),得到了答案\(ans\),由于下一步\(b = 0\), 程序退出.
整体来看,\(ans\) = \(3^1 \times 3^4 \times 3^{16}\) = \(3^{21}\),其中指数 \(1,4,16\) 恰对应 \(10101\)中\(1\)的位置(\(2^0,2^2,2^4\)).
曾经思考快速幂利用二进制加速,那么利用更高进制的加速岂不更快?
思考一下便打消了这种想法:其他进制不如二进制方便.二进制将数分解为\(1 \times 2^a+ 1 \times 2^b......\) 前面有默认系数1,可对于其他进制的系数则有(1,2,......), \(②\) 中的 \(base\) 根本积累不了.

浙公网安备 33010602011771号