相信童鞋们做题多了会发现,很多题都是要求次幂的。如果数据比较小,用int 或者long long 的暴力也是可以出结果的,但很多题就不尽如人意了,数据往往非常大,long long 可能都存不下,甚至还会爆内存,导致数据出错。
这时候就需要更快更省内存的算法——快速幂
快速幂快速幂,就是快!想象一下,求2^16,是2*2*2*...乘16个2快,还是((2*2*2*2) * (2*2*2*2)) * ((2*2*2*2) * (2*2*2*2)) 再算 (2*2*2*2) * (2*2*2*2). . .比较快。所以,快速幂的原理来了:求a^n,只要求a^(n/2) * a^(n/2)即可,以此类推,倒着算,当然,这是n为偶数的情况。n为奇数时只要ans*a即可
int sq(ll a,ll n)
{
if(n==1)
return a;
else if(n%2==1)
return (ll)pow(sq(a,n/2),2)*a;
else
return (ll)pow(sq(a,n/2),2);
}
这里判断次数是否为奇数,有多种方法(暂时我只知道两种):
① n%2(==1) ② n&1(==1) 因为&是与符号,在计算机中存储都为二进制数,只有n的尾数为1(即n为奇数)时,1&1=1,if条件才成立
有时次幂结果太大的,题上会要求取余,那么取余应该怎么做呢?
离散数学讲到:积的取余等于取余的积的取余。
举个例子:(a * b)%mod = (a%mod * b%mod)%mod
在次幂也同样适用,比如:2^3%mod = ((2%mod * 2%mod)%mod * 2%mod )%mod
看起来很复杂,但是写成算法就还好,注意不要少了取余的个数,少取一次就误差一点,少取n多次。。嗯。。。
int sq(ll a,ll n)
{
if(n==1)
return a%mod;
else if(n&1)
return ((ll)pow(sq(a%mod,n/2)%mod,2))%mod*(a%mod)%mod;
else
return ((ll)pow(sq(a%mod,n/2)%mod,2))%mod;
}
还有一种稍微优化一点的算法,省去了pow函数
ll sq(ll a,ll n)
{
if(n==1)
return a;
ll ans = sq(a,n/2)%mod;
if(n&1)
return (ans* ans)%mod * (a%mod) %mod;
else
return ans * ans % mod;
}
上面的方法是递归,还有一种迭代的写法
ll quick_pow(ll a, ll n)
{
ll ans=1;
while(n)
{
if(n&1)
{
ans=(ans*a)%mod;
n--;
}
n/=2;
a=a*a%mod;
}
return ans;
}