乘法爆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進制

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章