1. 程式人生 > 其它 >數學/數論專題-學習筆記:線性基

數學/數論專題-學習筆記:線性基

目錄

1. 前言

線性基,是線性代數中的一個板塊,專門處理異或問題。

注意作者是個 OIer,因此並不會涉及(或者是極少的)線性代數知識。

注意本文所講線性基跟向量無關。

前置知識:二進位制,位運算。

2. 詳解

2.1 定義與性質

線性基的定義如下:

給出一個數列 \(a_1,a_2,...,a_n\),若一個序列 \(d_1,d_2,...,d_k\) 滿足以下性質:

  • 所有原數列中的元素能夠異或出來的值 \(d\)
    中的數也能異或出來。
  • 滿足性質 1 的前提下,\(d\) 中的數不能異或出 0。
  • 滿足性質 2 的前提下,\(d\) 中的數最少。

那麼就稱 \(d\) 是原序列 \(a\) 的一組線性基。

注意上述性質中的異或指的是從數列中選出一些數一起異或。

實際上任意數列 \(a\) 都有至少一組線性基

2.2 構造線性基

這個方法需要用到一個性質:\(a \oplus b=c \Leftrightarrow a \oplus c=b\)

首先考慮將所有 \(a_i\) 轉成二進位制,然後從二進位制最高位開始掃,對於第 \(x\) 位,如果 \(d_x\) 不存在,那麼 \(d_x=a_i\),否則 \(a_i \gets a_i \oplus d_x\)

,一個一個插入即可。

Code:

void add(LL x)
{
    for (int i = 50; i >= 0; --i)
    {
        if (x & (1ll << i))
        {
            if (d[i] & x) x ^= d[i];
            else { d[i] = x; break ; }
        }
    }
}

那麼這份程式碼如何滿足上述 3 個性質呢?


性質 1:原序列能夠異或出來的數線性基也能夠異或出來。

性質 2:線性基內的數不能異或出 0。

這兩條性質都是根據 \(a \oplus b=c \Leftrightarrow a \oplus c=b\)

來證明的。

由於 \(x \oplus d_i = d_j \Leftrightarrow d_i \oplus d_j = x\),因此性質 1 得證。

性質 2 採用反證法:假設 \(d_i \oplus d_j \oplus d_k=0\)\(d_k\) 最晚插入。

這裡只討論 3 個數的理由是實際上你可以將 \(d_i\) 看成多個數異或。

上式等價於 \(d_i \oplus d_j= d_k\)

於是根據程式碼,\(d_k\) 不應該被插入線性基,矛盾。


性質 3 的證明:

顯然對於所有存在的 \(d_i\) 而言,第 \(i\) 位二進位制位一定是 1。

既然如此,如果刪去任何一個數,都會導致有一位二進位制位空缺,因此這些數是必要的,同時又是最少的。

3. 應用

3.1 最大值問題

該問題的詳述描述如下:給出數列 \(\{a_i\}\),從中選一些數使其異或結果最大。

根據線性基的性質 1,我們可以構造線性基。

構造之後直接暴力按照 \(d_i\) 從大到小列舉,然後看一下跟答案異或能否使答案變大,能就異或。

實際上就是一個貪心的思想。

為什麼這樣貪心是對的呢?

如果第 \(i+1\) 位通過異或變成了 1,即使 \(1-i\) 位通過異或都變成了 0,答案也一定是增大的。

因此貪心是正確的。

3.2 最小值問題

這個問題有兩類:

第一類問題:問線性基能異或出的最小值。

這個直接就是最小的 \(d_i\),因為最小的 \(d_i\) 無論異或誰都會變大。

第二類問題:問原序列能異或出的最小值。

這個還需要看一下有沒有元素插入失敗,如果有就是 0,否則還是最小的 \(d_i\)

3.3 第 k 小問題

該問題的詳細描述如下:給出序列 \(\{a_i\}\),取出任意數進行異或,問能異或出的所有值的第 \(k\) 小。

首先我們需要對線性基做一個處理。

對於每一個 \(d_i\),如果 \(d_i\) 二進位制表示第 \(j\) 位為 1,那麼 \(d_i \gets d_{j-1} \oplus d_i\)

然後對 \(k\) 做二進位制拆分,如果第 \(i\) 位為 1,那麼答案異或上 \(d_i\)

這樣做的正確性就是考慮到 \(d_i\) 實質作用是提供最高位的 1,因此只要所有 1 能夠跟 \(k\) 對應答案就是第 \(k\) 小。

實際上轉換後的線性基還是線性基。

3.4 異或和問題

詳細描述:給出序列 \(\{a_n\}\),選若干個數異或,問可能的結果的和。

首先得出線性基,設大小為 \(s\),列舉每一個二進位制位 \(d\),如果存在一個線性基中的數,該位為 1,那麼這位的貢獻是 \(2^d \times 2^{s-1}\),所有貢獻加起來即可。

正確性證明:\(2^d\) 是這一位的值,\(2^{s-1}\) 是別的位能異或出的結果種數,保證結果種數互不相同是因為保證個數最小,此時就保證了不會出現兩組不同的數,其異或值相同。

4. 總結

線性基的三大性質:

  • 所有原數列中的元素能夠異或出來的值線性基中的數也能異或出來。
  • 線性基中的數不能異或出 0。
  • 線性基中的數最少。

構造方式:首先考慮將所有 \(a_i\) 轉成二進位制,然後從二進位制最高位開始掃,對於第 \(x\) 位,如果 \(d_x\) 不存在,那麼 \(d_x=a_i\),否則 \(a_i \gets a_i \oplus d_x\),一個一個插入即可。

最大值問題:貪心從大到小求解。

最小值問題:最小 \(d_i\) 或者是 0。

\(k\) 小問題:轉換線性基後直接二進位制拆分。

異或和問題:列舉二進位制位後算貢獻 \(2^{d} \times 2^{s-1}\)