不怕溢出の乘法取模【转】

Θ ( 1 ) Θ(1) Θ(1)模取乘

分析

我们把两个 1 0 18 10^{18} 1018 的数乘起来会发生什么?会炸掉?会循环, 9223372036854775807 + x 9223372036854775807+x 9223372036854775807+x 会变成 − 9223372036854775808 + x − 1 −9223372036854775808+x−1 9223372036854775808+x1 (因为 − 9223372036854775808 − 1 = 9923372036854775807 -9223372036854775808-1=9923372036854775807 92233720368547758081=9923372036854775807 )。

怎么规避负数然后取模呢?

这样: − 9223372036854775808 + a b − 1 − ( − 9223372036854775808 + ⌊ a b c ⌋ × c − 1 ) = a b − ⌊ a b c ⌋ × c = a b m o d    c −9223372036854775808+ab−1−(−9223372036854775808+⌊\frac{ab}{c}⌋×c−1)=ab−⌊\frac{ab}{c}⌋×c=ab\mod c 9223372036854775808+ab1(9223372036854775808+cab×c1)=abcab×c=abmodc

如果 l o n g   d o u b l e long\space double long double 也救不了你的话就算了。

代码

typedef long long LL;
LL mul(LL a,LL b,LL c)
{
	return ((a*b-(LL)((long double)a/c*b+1e-8)*c)%c+c)%c; 
}

版权声明:本文为CSDN博主「C20182030Epic」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。


备注

上面的说法好像并不完全正确?

因为 a b ab ab 可能“爆很多圈”,也就是说如果 a b = 1 0 36 ab=10^{36} ab=1036 的话……?

所以作者认为,原理应该是:

  • 第一点, 0 ≤ A − B < C ⇒ ( A   m o d   C ) − ( B   m o d   C ) ∈ { A − B + k C ∣ k ∈ { 0 , 1 } } 0\le A-B<C\Rightarrow(A\bmod C)-(B\bmod C)\in\{A-B+kC|k\in\{0,1\}\} 0AB<C(AmodC)(BmodC){AB+kCk{0,1}}

很简单的道理:

  • B = k C + m ( 0 ≤ m < C ) B=kC+m(0\le m<C) B=kC+m(0m<C)
  • A = k C + m + n ( 0 ≤ n < C ) A=kC+m+n(0\le n<C) A=kC+m+n(0n<C)
  • A   m o d   C ∈ { m + n , m + n − C } A\bmod C\in\{m+n,m+n-C\} AmodC{m+n,m+nC}
  • B   m o d   C = m B\bmod C=m BmodC=m

所以得证。

  • 第二点,“溢出”的本质是 x x x 变为 x   m o d   2 64 x\bmod 2^{64} xmod264

  • 第三点,无论如何, a b   m o d   c = a b − c ⌊ a b c ⌋ ab\bmod c=ab-c\lfloor\frac{ab}{c}\rfloor abmodc=abccab

将第三点中的 a b ab ab 当做 A A A c ⌊ a b c ⌋ c\lfloor\frac{ab}{c}\rfloor ccab 当做 B B B 2 64 2^{64} 264 当做 C C C ,代入第一点,即可证明。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值