「線性基」學習筆記

這裏指OI裏的線性基,用來解決與異或相關的問題。spa

線性基是一個整數集合對應的一個集合,其異或值域與原序列徹底相同(很少很多)。所謂異或值域,就是在集合中選擇任意子集的異或和的全部取值。這樣一來,就異或和意義下,這兩個集合就徹底等效了。code

異或的性質blog

交換律:$a \oplus b = b \oplus a$class

結合律:$a \oplus (b \oplus c) = (a \oplus b) \oplus c$二進制

自反性:$a \oplus a = 0$方法

異或能夠理解爲返回某兩位是否不一樣,或者理解爲不進位的加法。集合

構造線性基di

當線性基內的元素的異或和可以表示出原集合內的每一個元素時,它們的值域就必定相同了。由於考慮原集合中若干個元素的異或和時,只須要在線性基中選出對應的子集表示原集合被選中的每一個元素而後異或起來就能夠了。對於線性基內的一個元素被選屢次的狀況,根據自反性能夠抵消。co

假設要維護的數的二進制都是$L$位或更少的,咱們考慮在線性基中維護$L$個元素,其中第$i$個是$i$位的(保證開頭是1)。這樣的話,線性基內的元素必定是互不相同的。void

假設如今要往線性基里加入一個元素$x$。咱們想在線性基里加上若干元素(或不變),使得從線性基裏選一個子集可以表示出$x$。根據自反性,也就是要在線性基中找出一個子集使得其與$x$的異或和爲0。也就是要選出幾個元素抵消$x$。既然線性基內每個的開頭位都是不同的,咱們就很好判斷——咱們從高到低考慮$x$的第$i$位,若是是0那麼一定不能選元素$i$(因爲咱們從高到低考慮,選$i$就永遠沒法抵消掉這一位);若是是1那麼必須選元素$i$(因爲咱們從高到低考慮,不選$i$就永遠沒法抵消掉這一位),選了$i$以後,問題轉化爲$x$與這個元素異或以後的值$x'$與剩餘元素的異或和要是0,確定有$x>x'$,所以繼續按相同的方法作就好了。若是發現某一位的線性基不存在,那麼直接將其設爲$x$就好了。挺自然的。

線性基內的元素一旦肯定就不會修改了。

inline void insert(int x){ for(int i = 50; i >= 0; --i){ if(x & (1ll<<i)){ if(!basis[i]){ basis[i] = x; break; } x ^= basis[i]; if(!x) break; } } }

最大值

要求一個集合裏元素的最大異或和,那麼先建線性基。

線性基值域的最大值怎麼求?從最高位到最低位貪心。先將$ans$設爲0,而後從高到低去異或線性基裏的元素。若是當前位是1那確定要選,這個沒問題,$ans= ans \oplus basis_i$;若是當前位是0呢?那就若是$ans \oplus basis_i > ans$則異或。由於不管如何第$i$位不能變成1,那麼就先設法保證後面能更大。若是到了後面能把一位從0變成1,那確定會去作;反之若是後面沒這個能力,而卻經過這一步使0變成1了,那確定更優了。

值域大小

線性基中的元素各不相同,所以各子集的異或和也各不相同。答案是$2^{size}$。反證法——若是存在兩個子集異或和相同,那麼這兩個子集異或和爲0。經過結合律,咱們知道若是從這兩個子集中拿出一個元素$k$,其與剩餘部分的異或和相同,也就是剩餘部分能表示$k$,這個元素沒必要存在在線性基裏。

相關文章
相關標籤/搜索