快速乘

快速乘

在我们进行乘法运算的时候,很多情况下会爆\(long\:long\),所以我们急需寻找一种高效的方法来完成乘法运算并且不会爆\(long\:long\)

一、复杂度为\(o(logN)\)的快速乘

移位快速乘,思想是把\(a\times b\%p\)中的\(b\),对其进行二进制拆分,把\(b\)拆成二进制形式。\(a\times b=C_{k-1}\times a\times2^{k-1}+C_{k-2}\times a\times2^{k-2}+\dots+C_{0}\times a\times2^{0}\),其中\(c\)表示二进制数位。

例如:\(21\times13\),将\(13\)转化成二进制\(1101\),则就是\(20\times2^0+20\times2^2+20\times2^3\)。(类似于快速幂)

typedef long long ll;
ll qmul(ll n, ll b, ll mod){
	ll res = 0;
	while(n){
		if(n & 1) res = (res + b) % mod;
		b = (b + b) % mod;
		n >>= 1;
	}
	return res % mod;
}

二、复杂度为\(O(1)\)的快速乘

利用的是很简单的一个浮点数类型。\(long\:double\)能保证数字的精确程度,然后再把这个数字进行计算。计算的方式很简单,\(a\times b\%p=a\times b-[\frac {a\times b}{p}]\times p\)

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll qmul(ll x, ll y, ll mod){
	ll temp = (ld)x / mod * y;
	ll res = (ull)x * y - (ull)temp * mod;
	return (res + mod) % mod;
}

看到这份代码有没有感到十分奇怪? 它直接用了乘法操作的啊? 这不直接爆了吗?但是它就是可以直接算出正确答案来。因为它很巧妙的运用了自动溢出这个操作,我们的代码中的\(temp\)就表示 \(⌊\frac{x\times y}{p}⌋\),所以我们要求的就变成了 \(x\times y−⌊\frac{x\times y}{p}⌋\times p\) ,虽然这两个部分都是会溢出的,但(\(unsigned\))保证了它们溢出后的差值基本不变,所以即使它会溢出也不会影响最终结果的!

posted @ 2021-05-30 16:41  h星宇  阅读(199)  评论(0编辑  收藏  举报