快速幂是一种简单常用的小算法,主要用途是快速进行乘方运算。其时间复杂度可以达到O(logn)。
算法介绍
对于乘方运算
最直接的做法,将这n个2进行相乘,即要进行n-1次运算。时间复杂度是O(n-1)。
快速幂思路,如果n是偶数,先计算,再用两个进行相乘(这里用到二分的思想)。如果n是奇数,则 = * *2 。如果 n = 0 , 结果就是1。 不难想到,我们可以用递归来实现这个算法。
递归代码
long long qpow(int a, int n)
{
if (n == 0)
return 1;
else if (n % 2 == 1){
int temp = qpow(a,n/2);
return temp*temp*a;
}
else
{
int temp = qpow(a, n / 2);
return temp * temp;
}
}
注意,这里的temp是必须的,因为如果不把的结果记录下来,就会计算两次,这个代码的时间复杂度提高了。(a是底数)
非递归的方式
递归虽然美妙且好写,但递归会带来多余的空间开销,在所以我们有必要讨论一种非递归的方法,用循环。
我们来看,我们换一个角度看这个10,把它看成二进制,这时候我们的式子就是(注意这里的1010是10的二进制表示)。我们再对这个式子进行拆分,写成。(所有的乘方运算都可以拆成这样的表达)
上代码
long long qpow(int a, int n)
{
long long result = 1;//存结果
while(n){
if(n&1)result *= a;//如果n的最低位是1,加上这个结果(位运算)
a *= a;
n>>=1;//最低位处理完毕,换下一位处理
}
return result;
}
拓展
一般来说,如果我们只是单纯的想进行乘方运算,可以直接调用内置函数计算。那么是不是快速幂对我们来说就没有用了呢?并不是
做题的时候,常常遇到对结果取模的情况。如果我们乘方运算的结果连long long 都存不下的时候,快速幂就派上用场了。我们可以在计算的过程中不断的对中间结果区模,保证我们的最终结果不会越界。我们有如下公式。((m%mod)*(n%mod))%mod=(n*m)%mod。运用这个式子,结果就不会爆了。
来道题
参考代码:
#include <iostream>
#include <cmath>
typedef long long ll;
const ll mod = 99824353;
using namespace std;
ll qpow (ll k) {
int ans = 1, base = 2;
while (k) {
if (k & 1) ans = (ll)ans * base % mod;
base = (ll)base * base % mod;
k >>= 1;
}
return ans;
}
int main()
{
ll n;
cin>>n;
n--;
if(n==0)cout<<0;
else if(n==1)cout<<1;
else cout<<(ll)(qpow(n-2)*n%mod*(n+1)%mod)%mod;
}
讲一下思路:
杨辉三角的第n行的数实际上就是的各项系数。用排列组合的方式展开,求导,可以得到结果表达式n(n+1)*2^(n-2)。然后用上面的快速幂(记得取模)。