慢速乘和快速乘简单回顾和整理

慢速乘

  • 这种方法常常用在快速幂里面,替换整数乘法的部分,因为两个大整数相乘可能直接爆掉 l o n g   l o n g long\ long long long,原理如下
  • 因为一个数总是有唯一的二进制表示,所以我们把指数表示成二进制,比如 a × 3 a\times3 a×3,那么因为 3 = ( 11 ) 2 3=(11)_2 3=(11)2,所以 a × 3 = a × 2 + a × 1 a\times3=a\times2+a\times1 a×3=a×2+a×1,所以可以很自然的写出程序
typedef long long ll;
ll slowmul(ll x, ll y, ll mod){
    
    
    ll ans = 0;
    while(y){
    
    
        if(y & 1){
    
    
            ans = (ans + x);
            if(ans > mod) ans %= mod;
        }
        x = 2 * x % mod;
        y >>= 1;
    }
    return ans;
}
  • 时间复杂度是 O ( l o g ( y ) ) O(log(y)) O(log(y)),因为通常情况下 y y y都极大,而且需要进行多次乘法,所以速度相对比较慢,不过这种方法基本不会出现溢出问题,因为把一个数一个一个的加再取模已经是优化到极限了,如果还会溢出,那就只能用高精度算法

快速乘

x y % p = x y − ⌊ x × y p ⌋ × p xy\%p=xy-\lfloor \frac{x\times y}{p}\rfloor\times p xy%p=xypx×y×p

  • 根据取模的性质有上述等式成立,然后就可以用一种神奇的溢出方式解决这个问题,但是好像数字过大时候可能会有误差,慎用此法
  • 记一下,参考2009年成都七中骆可强国家集训队论文——论程序底层优化的一些方法与技巧
typedef long double ld;
ll ksc(ll x,ll y,ll p){
    
    
	ll z=(ld)x/p*y;
	ll res=(ull)x*y-(ull)z*p;
	return (res+p)%p;
}

猜你喜欢

转载自blog.csdn.net/roadtohacker/article/details/120831431