【黑科技】O(1)快速乘

要理解 O ( 1 ) O(1) O(1)快速乘,首先要知道一般的整数取模怎么用乘除法和减法实现,比如 a % b a\%b a%b,在整数除法下它等价于 a − a / b × b a-a/b\times b aa/b×b

那么这里快速乘的实现是什么样的呢?


代码:

inline ll mul(ll a,ll b,ll mod){
	return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;
}

l o n g l o n g long long longlong类型的溢出其实相当于自动取相反数和自动取模。而快速乘的正确性保证就是取模的时候的模数是一定的(用脚趾头想都猜得到)

可以看到,这里用 l o n g d o u b l e long double longdouble类型计算出了 a × b / m o d a\times b/mod a×b/mod,同时避免了本来可能的一次溢出 a × b a\times b a×b,这次溢出是可能导致计算错误的(因为后面有除法,所以不能保证正确性),显然 a / m o d a/mod a/mod b b b相乘仍然可能导致溢出,但是这次溢出无关紧要。因为在取模可以进行除法。

而转回 l o n g l o n g long long longlong就是为了最后能够取模。
(浮点数不可能取模)

而由于两边都可能有或没有溢出,而溢出时取的模数是一定的,所以我们将他们相见后可能会得到的答案一定在 64 64 64位带符号长整形范围内,并且只可能是正确的余数 r e m a i n d e r remainder remainder r e m a i n d e r − m o d remainder-mod remaindermod

实际上,笔者并不建议在比赛中使用 O ( 1 ) O(1) O(1)快速乘,除非你特别需要卡常数,毕竟这浮点的精度问题总有点让人不放心。 (据说 D Z Y O DZYO DZYO快速乘偶尔写的这个没有被卡过)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值