数论2——快速幂

a的b次方怎么求

pow(a, b)是数学头文件math.h里面有的函数

可是它返回值是double类型,数据有精度误差

那就自己写for循环咯

LL pow(LL a, LL b){//a的b次方
    LL ret = 1;
    for(LL i = 1; i <= b; i ++){
        ret *= a;
    }
    return ret;
}

完美

可是题目是b的范围是1 <= b <= 1e9(#°Д°)

超时,妥妥的。。。

看个例子

比如计算

2*2*2*2*2*2*2*2*2*2*2

可以这样算

原式=4*4*4*4*4*2

=8*8*4*2

=16*4*2

你看,相同的可以先合并,减少计算步骤

如果题目说数据很大,还需要求余,那么代码就可以这么写

LL pow_mod(LL a, LL b){//a的b次方
    if(b == 0) return 1;
    LL ret = pow_mod(a, b/2);
    ret = ret * ret % MOD;
    if(b % 2 == 1) ret = ret * a % MOD;
    return ret;
}

这是递归写法

然后还有递推写法

LL pow_mod(LL a, LL b){//a的b次方
    LL ret = 1;
    while(b != 0){
        if(b % 2 == 1){
            ret = (ret * a) % MOD ;
        }
        a = (a * a ) % MOD ;
        b /= 2;
    }
    return ret;
}

对于位运算熟的小盆友,还可以写成位运算形式,速度又快,又好理解,在加一个求余p,代码如下

LL pow_mod(LL a, LL b, LL p){//a的b次方求余p 
    LL ret = 1;
    while(b){
        if(b & 1) ret = (ret * a) % p;
        a = (a * a) % p;
        b >>= 1;
    }
    return ret;
}

有了快速幂,于是,快速乘诞生了

LL mul(LL a, LL b, LL p){//快速乘,计算a*b%p 
    LL ret = 0;
    while(b){
        if(b & 1) ret = (ret + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return ret;
}

(*´Д`*)快速乘应该不怎么会用,无意义的东西,说不定哪天用的上

原文地址:https://www.cnblogs.com/xzxl/p/7353836.html