快速幂+大数乘法取模

14 篇文章 0 订阅
10 篇文章 0 订阅

快速幂:

<math.h> 中自带的 pow 函数在调用时需要一系列类型转换;数值并不是严格精确,存在误差;执行效率低。最好不要用。

然而自己用累乘法写的朴素函数执行效率低下,时间复杂度 o\left ( n \right ) 。

2^{k}-ary 算法 (Russian\, Peasant\, algorithm) , 是一种高效的快速幂算法,时间复杂度 o\left ( \log N \right ) 。

原理:

求 x^{n} 时,朴素方法需要累乘 n 次。假如 n 是 2 的指数型,可以表示为 n=2^{k} ,所以可以转化成:

x^{n}=\left ( \left ( x^{2} \right ) ^{2}\right )\cdots 

就压缩到了 k 次平方运算。

可以把这个方法推广到任意 n , 把 n 转化为二进制的形式:

n=2^{k1}+2^{k2}+2^{k3}+2^{k4}+\cdots  

那么

x^{n}=x^{^{2^{k1}}}x^{^{2^{k2}}}x^{^{2^{k3}}}x^{^{2^{k4}}}\cdots

所以只需要求到最高位的 x^{^{2^{k}}} 便可。

举个例子,求  x^{37}   , 37 的二进制为 100101 ,每个 1 的权依次是 32 、4、1 ,所以就有:

x^{37}=x^{32}x^{4}x^{1}

代码:

ll mod_pow(ll x, ll n, ll mod) {   //挑战
    ll res = 1;
    while (n > 0) {
        if (n & 1) res = res * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return res;
}

还有一种递归的实现:

ll mod_pow(ll x, ll n, ll mod) {    
    if (n == 0) return 1;
    ll res = mod_pow(x * x % mod, n / 2, mod);
    if (n & 1) res = res * x % mod;
    return res;
}

大数乘法取模:

有一点需要注意,就是在计算 x * x % mod 和 res * x % mod 时,由于 x 与 res 都会很大,直接相乘可能溢出 long long 的数据范围,此时就需要用大数乘法取模的方法。

代码:

typedef long long  ll;

ll mod_mult(ll a, ll b, ll mod) { 
    a %= mod;
    b %= mod;
    ll ans = 0;
    while (b > 0) {
        if (b & 1) {
            ans += a;
            if (ans >= mod)
                ans -= mod;
        }
        a <<= 1;
        if (a >= mod) a = a - mod;
        b >>= 1;
    }
    return ans;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值