快速乘總結

2022-01-10 00:54:26 字數 1682 閱讀 8800

因為我們知道乘法有的時候會溢位,即使是 \(long\ long\) 也可能在乘法時因為結果過大溢位(當模數也是 \(long\ long\) )。所以我們需要尋找一種能高效完成乘法操作並且不會爆 \(long\ long\) 的演算法,也就是快速乘。本文也將對幾種常用快速乘及其優化技巧做個總結。

我們知道乘法其實就是把很多個加法運算合到一起。現在我們的乘法會爆範圍,那我們就把它轉化為加法。但是我們不可能乙個乙個的加,這樣複雜度會是 \(o(n)\) 級別。所以我們模仿2進製加法操作來完成。(這點和快速冪相同)

inline ll ksc(ll x, ll y, ll p) 

return res;

}// ll 表示 long long

/**************************====*/

//寫法優化

inline ll ksc_best(ll x, ll y, ll mod)

當然我們不一定要仿照2進製,也可以是其他進製,只要中間算每一位上數字代表值時不會爆 \(long\ long\) 就行!

__int128是c++自帶的乙個資料型別,顧名思義,它可以裝下 \(2^\) 級別的大資料,而且可以直接進行各種加減乘除之類的操作(複雜度很接近 \(o(1)\) ),不過它需要手寫輸出(但其實我們只需要在運算時用一下就可以了,就像下面這樣:)

ll ans = ((__int128)x * y) % mod;
不過有一點遺憾的就是:比賽中基本上不會允許使用這個資料型別的

這個東西最初我感覺很不靠譜,但它就是能算出來正確答案。它就是用\(long\ double\) 來進行優化取模運算。讓我們先看一**實現吧:

inline ll ksc(ll x, ll y, ll p) 

// ll 表示 long long

// ld 表示 long double

// ull 表示 unsigned long long

// 一種自動溢位的資料型別(存滿了就會自動變為0)

看到這份**有沒有感到十分奇怪? 它中間是直接用了乘法操作的啊!這不直接爆掉了嗎?

但是它就是可以算出正確答案來。因為它其實很巧妙的運用了自動溢位這個操作,我們的**中的z就表示\(⌊x×y/p⌋\) ,所以我們要求的就變成了 \(x×y−⌊x×y/p⌋×p\) ,雖然這兩個部分都是會溢位的,但(\(unsigned\))保證了它們溢位後的差值基本不變,所以即使它會溢位也不會影響最終結果的!

我們知道快速乘的原理其實就是乘法轉加法(上面這種不算),但是這是可以根據題目性質靈活轉變的,我們如何轉成加法決定了我們的複雜度,就像如果模數並沒有超過 \(int\) 範圍很多,那我們適當的運用乘法分配律可以讓複雜度非常接近 $o(1) $:

inline ll ksc(ll x, ll y, ll p)
在保證運算不會爆 \(long\ long\) 的前提下,我們可以盡量優化其複雜度,就像上述**在模數小於 \(10^\) 的情況下完全變成了 \(o(1)\) 級別,在某些題目中會十分優秀!

miller rabin 判大質數

pollard rho 大數因子尋找

bsgs 大步小步演算法

快速乘總結

因為我們知道乘法有的時候會溢位,即使是 long long 也可能在乘法時因為結果過大溢位 當模數也是 long long 所以我們需要尋找一種能高效完成乘法操作並且不會爆 long long 的演算法,也就是快速乘。本文也將對幾種常用快速乘及其優化技巧做個總結。我們知道乘法其實就是把很多個加法運算...

快速乘學習總結

當兩個相乘數x y較小時,我們可以直接x y p。但當兩個數都為long long型別呢?很明顯直接相乘會爆範圍 其實乘法可以轉換成加法,我們可以邊加變取餘 但不是直接 y 個 x 乙個乙個相加,因為這樣絕對會超時。我們可以將 y 進行進製轉換 實現 ll q mod ll x,ll y,ll p ...

快速乘與快速冪總結

快速乘 a b p while b 把b看成二進位制 a a 2 p 2 式 要採用遞推 取模的方法得到 b b 1 右移一位 printf lld ans 推導過程 a 2 k1 a 2 k2 a 2 k3 a 2 kn p a 2 k1 a 2 k2 a 2 k3 a 2 kn 1 p a 2 ...