快速幂算法

 快速幂是一种简单常用的小算法,主要用途是快速进行乘方运算。其时间复杂度可以达到O(logn)。

算法介绍

对于乘方运算2^{n}

最直接的做法,将这n个2进行相乘,即要进行n-1次运算。时间复杂度是O(n-1)。

快速幂思路,如果n是偶数,先计算2^{n/2},再用两个2^{n/2}进行相乘(这里用到二分的思想)。如果n是奇数,则2^{n} = 2^{n/2} *2^{n/2} *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是必须的,因为如果不把2^{n/2}的结果记录下来,就会计算两次2^{n/2},这个代码的时间复杂度提高了。(a是底数)

非递归的方式

递归虽然美妙且好写,但递归会带来多余的空间开销,在所以我们有必要讨论一种非递归的方法,用循环。

我们来看2^{10},我们换一个角度看这个10,把它看成二进制,这时候我们的式子就是2^{1010}(注意这里的1010是10的二进制表示)。我们再对这个式子进行拆分,写成2^{1000}*2^{0010}。(所有的乘方运算都可以拆成这样的表达)

上代码

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行的数实际上就是\left ( 1+x \right )^{n-1}的各项系数。用排列组合的方式展开,求导,可以得到结果表达式n(n+1)*2^(n-2)。然后用上面的快速幂(记得取模)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值