快速幂和大数乘积取模

  1. 快速幂(在lgn时间计算 x y x^y xy
    步骤,将y转化为二进制,举个具体例子,假设y=13 = 1101(2),有
    x 13 = x 1101 = x 2 3 ⋅ 1 ⋅ x 2 2 ⋅ 1 ⋅ x 2 1 ⋅ 0 ⋅ x 2 0 ⋅ 1 x^{13} = x^{1101} = x^{{2^3}\cdot1}\cdot x^{{2^2} \cdot1} \cdot x^{{2^1}\cdot0} \cdot x^{{2^0}\cdot1} x13=x1101=x231x221x210x201

可以看出,我们从低位到高位,依次取出y的每一位进行累计乘,将每次将基x = x * x, 得到如下代码

 long long Pow(long long x, long long y){
        long long res = 1;
        while(y){
            //累乘
            if(y & 1)
                res = fast(res, x);
            //叠加
            x = fast(x, x);
            //减少乘次数
            y = y >> 1;
        }
        return res;
    }

其中fast函数是一个大数乘法并对结果取模

    //乘法
    inline long long fast(long long x, long long y){
        return ((x % mod) * (y % mod)) % mod;
    } 

2.大数乘积取模
利用: ( x × y ) % m o d = ( ( x % m o d ) × ( y % m o d ) ) % m o d (x\times y) \% mod =((x \% mod) \times (y\%mod)) \% mod (x×y)%mod=((x%mod)×(y%mod))%mod
但这种情况只实用与mod在INT表示的范围类型内的数字,如果mod很大, ( ( x % m o d ) × ( y % m o d ) ) ((x \% mod) \times (y\%mod)) ((x%mod)×(y%mod)) 相乘还是有可能溢出,这种情况,就只能将乘法转换成加法进行操作

   long long fast(long long x, long long y){
        long long res = 0;
        x %= mod;
        y %= mod;
        while(y){
            if(y & 1){
                //加法代替乘法,防止越界
                res += x;
                if(res >= mod)
                    res -= mod;
            }
            y = y >> 1;
            x = x << 1;
            if(x >= mod)
                x -= mod;
        }
        return res;
    }

这段代码是一种快速乘法的算法,它的原理是利用二进制的位运算来将乘法转换为加法,从而避免溢出。

具体来说,假设我们要计算ab,我们可以将b转换为二进制表示,比如b=11,那么b的二进制是1011,那么我们可以将ab写成:

a ∗ b = a ∗ ( 2 3 ) ∗ 1 + a ∗ ( 2 2 ) ∗ 1 + a ∗ ( 2 1 ) ∗ 1 + a ∗ ( 2 0 ) ∗ 0 a*b = a*(2^3)*1 + a*(2^2)*1 + a*(2^1)*1 + a*(2^0)*0 ab=a(23)1+a(22)1+a(21)1+a(20)0

= ( a < < 3 ) + ( a < < 2 ) + ( a < < 1 ) + 0 = (a<<3) + (a<<2) + (a<<1) + 0 =(a<<3)+(a<<2)+(a<<1)+0

其中,<<表示左移运算符,即将一个数的二进制位向左移动一定的位数,相当于乘以2的相应次方。例如,a<<3就相当于a*8。

那么,我们可以用一个循环来实现这个过程,每次判断b的最低位是否为1,如果是,就将a累加到结果中;然后将a左移一位,将b右移一位(即除以2),直到b变为0为止。这样就完成了快速乘法的算法。

代码中的mod表示取模运算,即对结果进行求余数,这是为了防止结果过大而溢出。所以每次累加或者左移之后都要对mod取余。

代码中的&表示按位与运算符,即将两个数的二进制位进行逐位的与运算,只有当两个位都为1时才得到1,否则得到0。例如,11&1=1,因为11的二进制是1011,而1的二进制是0001,只有最低位都为1时才得到1。所以代码中用b&1来判断b的最低位是否为1。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值