這裡的矩乘並不狹隘地專指一般矩陣乘法,而可以指所有與一般矩乘一樣具有結合律的二元矩陣運算。
例:定義一種 01 矩陣乘法 \(a\cdot b=c\) 為下面的 c++ **
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
for (int k = 1; k <= n; ++k)
c[i][j] |= a[i][k] & b[k][j];
其中 \(a,b,c\) 都是 01 矩陣。
顯然這種矩乘是具有結合律的,即符合 \((a\cdot b)\cdot c=a\cdot(b\cdot c)\)
因為是 01 矩陣,可以用 bitset 優化
於是上面的**顯然與下面這份等價
std::bitseta[n], b[n], c[n];
for (int i = 1; i <= n; ++i)
for (int k = 1; k <= n; ++k)
for (int j = 1; j <= n; ++j)
if (a[i][k])
c[i][j] |= b[k][j];
即交換一下 k 與 j 的迴圈。
仔細一看,發現最後一維列舉 j 時,a[i][k]
不受其影響,同時c[i]
與b[k]
對齊了
於是利用 bitset 自帶的運算我們可以寫成
std::bitseta[n], b[n], c[n];
for (int i = 1; i <= n; ++i)
for (int k = 1; k <= n; ++k)
if (a[i][k])
c[i] |= b[k];
因為 stl 封裝的內部優化肯定比我們自己在外部手寫的優很多
或者更準確地說
時間複雜度從 \(o(n^3)\) 降為了 \(o(n^3/\omega)\) ,其中一般 \(\omega\) 為 32 或 64 ,與計算機位數有關。
一些例題:
cf567d flights for regular customers
usaco07nov cow relays g
noi online #3 提高組 魔法值
noi2020 美食家
Sajam(01翻轉 bitset優化)
原題 題意 n n的01矩陣,你可以無限次翻轉一行或者一列,可以最多翻轉k k n 次乙個點。問是否可以全部翻轉成0。解析 k n說明至少有一行不會被翻轉單個點,或者k n時每行翻轉乙個點。那麼列舉每一行為那一行,將其他行與之對比 可以翻轉後再對比 不同的數量就是需要翻轉單個點的數量。因為有列翻轉,...
數學蒟蒻的矩乘小結
a b a b left 1 2 3 4 5 6 end right left 1 4 2 5 3 6 end right left 14 32 32 77 end right a b 1 23 4 56 a b a ba b的理解是,b bb矩陣是2 22個3 33維向量,a aa矩陣提供了3 3...
CF575A Fibonotci(矩乘套路題)
點此看題面 假設 m 0 則第 i 個位置的轉移矩陣就是 begin 0 s 1 s end 那麼就是要求第 2 sim k 個矩陣的總乘積,顯然發現它的週期為 n 這種東西隨便做做就好了,相信大家都會,畢竟並不是此題的核心所在。考慮乙個給定的 s i 影響到的是 s 和 s 因此我們可以找出 2m...