線性基真的是乙個非常神奇的演算法。
它可以用於求解乙個集合內的最大異或和,而且效率極高,是\(o(n\ log\ maxnum)\)的時間複雜度。
所以,它還是十分值得一學的。
什麼是線性基?
對於乙個陣列\(a_1a_2...a_n\),我們可以用\(num_1num_2...num_\)來記錄第乙個二進位制下最高位出現在第\(i\)位的數字。
並通過這個\(num\)陣列,來求出這個陣列中的最大異或和。
關於線性基的構造,其實也是十分巧妙的。
我們先找到當前插入的數\(x\)二進位制下的最高位\(i\),然後對此時\(num_i\)是否為\(0\)進行分類討論:
由於\(x\)的最高位肯定是遞減的,所以單次時間複雜度是\(o(log_)\)的,總複雜度是\(o(n\ log\ max(a_i))\)的。
關於如何詢問最大異或和,其實也是很簡單的。
我們從高位到低位列舉每乙個\(p_i\),並用\(ans\)記錄答案。
對於當前\(p_i\),我們有乙個貪心的策略:若\(ans\)
$num_i>ans$,則更新$ans$為$ans$
\(num_i\),否則就跳過。
這樣貪心乍一看彷彿漏洞百出,實際上仔細一想還是有一定道理的。
為什麼這樣貪心一定是對的呢?
首先我們要知道乙個最簡單的性質:對於\(num_i\),如果它不為\(0\),則它二進位制下最高位一定是第\(i\)位。
關於這一點的證明,可以結合上文線性基的定義與構造方式,這裡就不予證明了。
則不難想到,\(ans\)^\(num_i\)後被影響到的肯定是後\(i\)位,且第\(i\)位肯定是發生變化的。
所以,如果\(ans\)^\(num_i>ans\),我們就可以得到:原\(ans\)二進位制下第\(i\)位為\(0\),異或後的\(ans\)二進位制下第\(i\)位為\(1\)。
由於後續操作是不會影響到第\(i\)位及前面已操作位的大小的,所以第\(i\)位肯定越大越優。
於是就可以通過貪心來求解了。
關於為什麼\(ans\)^\(num_i\le ans\)就跳過不再處理,其實也是同理的。
除了這兩個比較基礎的操作,其實線性基還是有很多用途的,如:
關於這些操作,我也只是聽說過,因此這裡就不介紹了。
以【洛谷3812】【模板】線性基這道模板題為例,貼乙份**:
#include#define n 50
#define ll long long
using namespace std;
int n;
class fio
inline void read(int &x)
inline void read(ll &x)
inline void write(ll x)
}f;class class_linearbasis//線性基模板
}linearbasis;
int main()
線性基入門
線性基是乙個集合 也就是說線性基是對原集合的壓縮 首先,可以知道 對於集合a 將其中的ai i 1,n 用ai aj j 1,n 且j i 替換得到集合b 從集合a中選取任意多個數異或得到的值都能通過在集合b中選取一些數進行異或得到 證 從原集合a中選取一些數異或得到 x ak1 ak2 akm k...
線性基入門學習
前置技能點 線性相關,線性無關 張成 spa nspan span s ss的所有子集 包括空集 的異或和組成的集合,叫做集合s ss的張成。什麼是線性基 線性基可以理解為集合s ss在異或運算中的壓縮,即集合s ss的線性基中的元素進行異或運算可以表示出集合中的元素進行異或運算的所有結果。換句話說...
模板 線性基
難度較大,請勿棄療 給定n個整數 數字可能重複 求在這些數中選取任意個,使得他們的異或和最大。n 50sample input33 21sample output 3看上去莫名其妙地想貪心。給些定義 s 為無符號整數集 即s n 記為 xor sum s x or s um s s1 s2 s s ...