1. 程式人生 > 其它 >「筆記」線性基

「筆記」線性基

概念

線性基是向量空間的一組基,通常可以解決有關異或的一些題目。-Oi-wiki

線性基就是一個有著特殊性質的集合,在處理某些情況下的異或問題有著意想不到的效果。

假設我們用 \(p\) 陣列來存線性基。

線性基可以由給出的一組元素相互異或而來。

\(p_i\) 中的元素表示該元素二進位制下 \(1\) 的最高位是第 \(i\) 位。

性質

  • 線性基具有普通集合所具有的性質,即確定性、互異性、無序性。
  • 線性基中每個元素的最高位不同。(根據 \(p\) 陣列定義比較顯然。)
  • 線性基中沒有異或和為 \(0\) 的子集。(每個元素的最高位不同,異或起來最高位一定不會為 \(0\)。)
  • 線性基中任意多元素的異或和的值域等於原集合中任意多元素的異或和的值域。
  • 線性基在滿足上一個條件的情況下,所包含元素個數是最少的。
  • 線性基中不同的元素異或出來的值是不同的。

構造

一下情況都是在二進位制下進行。

假設插入一個元素 \(x\)

  • 從高位向低位判斷,直到遇到該元素某位上為 \(1\),設該位為 \(i\)
  • 然後判斷 \(p_i\) 是否有值,如果沒有把 \(x\) 存到 \(p_i\) 中,否則將 \(x\)\(p_i\) 異或然後重複上面的操作。(將 \(x\)\(p_i\) 異或後 \(x\) 的最高位上的 \(1\) 就沒了,至於變成了啥也無所謂了)

把所有元素都插入後,我們就得到了這組元素的線性基。

這樣構造的線性基滿足它該有的所有性質,\(p_i\)

陣列也符合定義。

Code:

void Insert(int k) {
    for(int i = Max; i >= 0; --i) { // Max 表示二進位制最高位
        if(!(k & (1ll << i))) continue;
        if(!p[i]) { p[i] = k; return ; }
        k ^= p[i];
    }
}

操作

求最大值

給你一堆元素,挑幾個異或起來,是他們的值最大,輸出最大值。

我們先用這組元素構造出線性基。然後貪心的進行選擇,選高位的肯定比低位的要更優。

所以我們從高位向低位遍歷,如果異或上 \(p_i\)

更優就異或。最後的結果就是要求的最大值。

為什麼能直接用?線性基的元素都是通過已知的元素異或而來,肯定是正確的。

Code:

int Query() {
    int res = 0; 
    for(int i = Max; i >= 0; --i) res = max(res, res^p[i]);
    return res;

求一個數是否能被表示出來

把這個數扔到線性基裡跑一邊就行。

每次挑這個數的最高位進行異或,都能把最高位消掉。

如果最後這個數為 \(0\) ,說明該數可以被表示出。

線性基合併

把一個線性基的每個元素插入另外一個線性基即可。

查詢嚴格次大值

先找到最大值,然後從低位向高位列舉,然後找到兩者都為一的異或上, 然後退出即可。

例題

下午再補先咕咕

鳴謝

題解 P3812 【模板】線性基 - rui_er

線性基知識整理 - Aliemo

線性基 - KnightL