乘法爆long long的解决方案

我们有两个数a,b,要求a*b%p的结果。

如果a和b虽然都不超过long long,但乘在一起就超过了怎么办呢?

这里提供两种解决方案,适用于两种不同情况。

1、用龟速乘。

我们来想想,a*b的本质是什么?是b个a相加对吧?

相信大家都学过快速幂,快速幂求的是b个a相乘,那么我们灵活改一下,把它变成b个a相加,应该很简单吧?

这样由于是一点一点加上去的,每次加都取模,所以就不会爆long long了。

这就是龟速乘,时间复杂度同快速幂一样,是log(b)的。

模板:

long long cheng(long long a,long long b)
{
	long long s=0;
	while (b)
	{
		if (b&1) s=(s+a)%Mo;
		a=(a+a)%Mo;
		b>>=1;
	}
	return s;
}

2、用一种我并不知道名字的黑科技

我们先来分析一下上面这种做法的优劣:

好处是只要a,b在long long内,无论它们乘起来多大,都可以做。

劣势是时间复杂度是log(b)的,比起正常乘法来太慢了。

 

那我们有没有时间复杂度是O(1)的呢?

当然有,下文便是。 

不过接下来提供的做法只适用于a*b没有超过long long太多的情况(即a,b并不算大,大概均在10^12左右)

设一个常数t。

令x1=a/t,x2=a%t

   y1=b/t,y2=b%t

显然a*b=(x1*t+x2)*(y1*t+y2)=x1*y1*t*t+x1*y2*t+x2*y1*t+x2*y2。

我们要让这中间两个数乘起来均不超过long long即可。

具体t的取值参照a,b的大小,可自行考虑。(例如a,b均小于10^12时,t=10^6为宜)

这样,就可以实现边乘边模始终不爆啦。

O(1)实现!

补充一下,这种做法的本质其实是把龟速乘的转二进制改成了转10^6进制

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值