異或線性基小記

spdarkle發表於2024-11-19

其實是 \(\mathbb{F}_{2}^n\) 空間的一個線性無關向量組。

前置知識

向量

定義 \(n\) 維向量 \(v=(v_1,v_2,\dots v_n)\) 為一個 \(n\) 元有序陣列,記作 \(v\in \mathbb{R}^n\),也即 \(n\) 維實數空間的一個向量。

定義如下運算:

  1. \(c\in \mathbb{R},v\in \mathbb{R}^n,cv=(cv_1,cv_2\dots cv_n)\),也就是每一維相乘,稱為數乘。
  2. \(v_1,v_2\in\mathbb{R}^n,v_1+v_2=(v_{1,1}+v_{2,1},v_{1,2}+v_{2,2}\dots v_{1,n}+v_{2,n})\)

線性組合與張成空間

定義向量集 \(V=\lbrace v_1,v_2,\dots,v_n\rbrace\),若存在 \(c_1,c_2\dots c_n\in \mathbb{R}\),滿足向量 \(x=\sum c_iv_i\),則稱 \(x\)\(V\)\(c_1,c_2\dots c_n\) 為權的線性組合,所有這樣的 \(x\) 組成的集合稱為 \(V\) 的張成空間,記作 $$\operatorname{span}(V)$$

線性相關

對於向量集 \(V=\lbrace v_1,v_2,\dots,v_n\rbrace\),若 \(\exists j,v_j\) 可以表達為 \(v_1,v_2\dots v_{j-1}\) 的線性組合(注意取到 \(j-1\) 即可)

定義:若向量集 \(B\) 線性無關,則稱 \(B=\operatorname{span}(B)\)​ 的一組基。

  • \(B\) 的任意真子集不是 \(\operatorname{span}(B)\) 的基
  • 對於任意 \(v\in \operatorname{span}(B)\),存在唯一的 \(c_1,c_2\dots c_n\),滿足 \(v\)\(B\)\(c_1,c_2\dots c_n\)​ 為權的線性組合
  • 對於任意線性有關集 \(V\),存在其真子集 \(B\) 滿足 \(\operatorname{span}(B)=\operatorname{span}(V)\)

一個線性空間可能有多組基。

異或線性基

其實是 \(\mathbb{F}_2^n\) 空間的一個 \(k\) 維子空間的基(指數域是 \(2\)\(n\) 維空間,算術意義上就是 \([0,2^n-1]\) 的整數)

本質:

異或是 \(\bmod 2\) 意義下的加法

將一個 \([0,2^n-1]\) 的整數的每一二進位制位看作取值為 \(0/1\) 的向量 \(v_i\),那麼整數就對應上了一個向量。

類似地,我們定義張成空間:

  • 定義序列 \(a\) 的張成空間 \(\operatorname{span}(a)\) 為從 \(a\) 中挑選若干數字可以異或得到的數字之和,換句話說就是 \(a\) 的所有子序列(可以空)元素異或和組成的集合

線性基的構造方法

構造線性基,我們考慮用增量法來構造線性基。假如現在要插入一個向量,從左向右不斷消去1,直到出現了第一個無法消去的1,說明這個向量無法用現在的幾組基底表示出來,所以將其插入線性基。

程式碼實現

ll d[65];
void ins(ll x){
    for(int i=60;i>=0;i--)
    if((x>>i)&1){
        if(d[i])x^=d[i];
        else{
            d[i]=x;break;
        }
    }
}

性質:

  1. 序列 \(a\) 的線性基為 \(\operatorname{span}(a)\) 的一組基。
  2. 線性基是線性無關向量組
  3. 線性基裡有值的元素個數所有張成空間是 \(\operatorname{span}(a)\) 的向量組裡最少的。
  4. \(B\) 為線性基,則 \(|\operatorname{span(a)}|=2^{|B|}\)

標準基,也稱上三角基

一個張成空間很可能不止一組基,而標準基尋求一種標準的表示方法。

我們將一般的線性基執行如下操作:

for(int i=60;~i;--i)if(d[i])for(int j=i-1;~j;--j)if((d[i]>>j)&1)d[i]^=d[j];

容易發現操作後的線性基同樣也是原張成空間的基,且滿足將該向量組寫為 \(01\) 矩陣後,每一行的最高位 \(1\) 滿足該列僅有這個位置是 \(1\)

類似於階梯型矩陣和簡化階梯型矩陣。

這相當有用。

應用

\(k\) 小異或和

\(k\) 從零開始。

線性基化為標準基,設其按大小排序後是 \(d_0,d_1,\dots,d_m\),則該異或和為將 \(k\) 二進位制分解後為 \(1\) 的位對應的 \(d\) 異或後的值。

讀者自證不難

特別的,最大異或和就是全部異或起來,而 \(\min_{x\in \operatorname{span}(B)}x\oplus v\) 就是將 \(v\) 嘗試插入線性基後剩下來的值。

線性基合併

直接暴力把一個線性基插入另一個線性基即可。

線性基求交

定義線性空間 \(V_i\) 的基底為 \(B_i\),現在我們希望求出 \(V_1\cap V_2\) 的基底 \(W\)

  • 引理:令 \(T=V_1\cap B_2\),若 \(B_1\cup(B_2/T)\) 線性無關,則 \(T\) 是所求的 \(W\) 之一。

    證明:考慮反面證明,若 \(T\) 非法則線性有關,設 \(v\in V_1\cap V_2\) 且不能被 \(T\) 表出。

    那麼有 \(v=x\oplus y,x\in T,y\in B_2/T\),且 \(y>0\)

    因為 \(x\in T\implies x\in V_1\),同時 \(v\in V_1\),所以 \(x\oplus v=y\in V_1\)

    \(y\) 就可以被 \(B_1\) 表出

    \(B_1\cup (B_2/T)\) 線性相關。

考慮如何求出 \(W\),可以考慮列舉 \(x:1\to |B_2|\)

  • \(b_x\in B_2\)

    1. \(b_x\) 可以被 \(B_1\cup \lbrace b_1,b_2\dots b_{x-1}\rbrace\) 表出

      \(b_x=p\oplus q,p\in V_1,q\)\(\lbrace b_1,b_2\dots b_{x-1}\rbrace\) 表出,則將 \(q\) 加入 \(W\)

    2. 否則不做任何操作。

證明這樣可以求出 \(W\),只需要證明 \(V_{B_2-W}\cap V_1=\lbrace 0\rbrace\) 即可。

\(x\in V_{B_2/W}\cap V_1,x>0\)

則有 \(x\) 可以被 \(B_1\) 以及 \(B_2/W\) 表出,那麼取出 \(B_2/W\) 裡下標最大的 \(b_k\),則有 \(b_k\) 可以被 \(B_2/W/\lbrace b_k\rbrace\cup B_1\) 表出,那麼與假設不符。

證畢。

struct node{
    int d[32];
    node(){
        memset(d,0,sizeof d);
    }
    void ins(int x){
        for(int i=31;i>=0;--i)if((x>>i)&1){
            if(d[i])x^=d[i];
            else {d[i]=x;return ;}
        }
    }
    bool count(int x){
        for(int i=31;i>=0;--i)if((x>>i)&1){
            if(!d[i])return false;
            x^=d[i];
        }
        return true;
    }
    node operator&(const node b)const {
        node tmpa;memcpy(tmpa.d,d,sizeof d);
        node uda=tmpa,res;
        for(int i=0;i<32;++i)if(b.d[i]){
            int x=b.d[i],sur=0,tag=1;
            for(int j=i;j>=0;--j)if((x>>j)&1){
                if(tmpa.d[j])x^=tmpa.d[j],sur^=uda.d[j];
                else {tmpa.d[j]=x,uda.d[j]=sur,tag=0;break;}//uda.d[i] 指該元素使用的 B_1 中元素 xor 和
            }
            if(tag)res.ins(sur);
        }
        return res;
    }
};

帶刪除線性基

肯定是離線的啦

考慮求出每個元素的刪除時間 \(t_i\),按加入時間順序將元素加入線性基,插入 \((v,t)\) 時,同樣依次掃描各個二進位制位,執行如下操作:

若當前線性基這一位的刪除時間早於 \(t\),將 \(v\) 與這一位互換(注意 \(t\) 也需要互換),並繼續向下插入

否則就異或後正常插入

查詢時就將時間早於當前時間的位不考慮即可。

當然可以自然擴充套件到字首線性基。

考慮對於原序列的每一段字首,維護一個字首線性基。

對於每個二進位制位,維護可以貢獻它的基底中下標最大的一個。

插入的時候如果存在基底,考慮將插入的數和基底中下標較小的一個繼續向下插入,另一個作為當前位的基底。

查詢只需要第 \(r\) 個字首線性基中下標大於等於 \(l\) 的基底。

線性基與無向圖路徑

核心:無向圖可以走回頭路,那麼一個環的異或值可以不耗任何代價得到

對於一個無向連通圖,有邊權,構建 DFS 樹後,將所有環的權異或組成一個線性基,具有以下性質

  • 這個線性基只需要所有返祖邊所對應簡單環異或和即可構建(其他環可以表達為這些環的複合)
  • \(u→v\) 的所有可能的路徑的異或值均可以用這兩者的簡單路徑的異或值與線性基中的值表出,這是因為走到一個環又走回去是可以抵消的,這時候產生貢獻的只有環。
  • 對於 \(u→v\) 所有路徑的異或值,用 \(B\) 表示所有返祖邊構成環的權值組成的線性基,則有將 \(d_u\oplus d_v\) 加入 \(B\) 後,\(B\) 的張成空間內的所有元素在原圖都能夠找到一條 \(u\to v\) 的路徑其異或值是這個(特判 \(0\)

相關題目

幸運數字

給定一顆樹,點有點權,多次詢問,給出 \((u,v)\),求樹上 \(u\to v\) 路徑選出任意多個點的點權異或和最大值

等價於求出 \(u\to v\) 路徑上所有點的點權構成的線性基。

可以利用字首線性基的方法做一個字尾線性基,詳細的說,求出線性基 \(b_i\) 表示 \(1\to i\) 路徑上所有點構成的線性基,每一位貪心保留深度較大的位。

那麼每次相當於是拿出 \(b_u,b_v\) 兩個線性基裡深度 \(\ge dep_{lca(u,v)}\) 的元素重組一個線性基即可

複雜度 \(O(n\log n\log V)\)

P 哥的桶

相當於給定 \(n\) 個線性基,支援動態在一個線性基裡插入一個值,以及詢問 \([l,r]\) 的線性基合併後的最大異或和。

線段樹暴力維護線性基合併即可,\(O(n\log^3 n)\)

新Nim遊戲

考慮從大到小插入線性基,如果插入失敗說明此數必選。

正確性:線性基上每一位儘可能讓更大的數字佔掉不劣。

CF1100F

相當於 P 哥桶的靜態版本,每個位置只有一個數。

一個 \(\log^2\) 的做法是考慮是靜態的,於是離線詢問,分治計算答案,一共執行 \(O(n\log n)\) 次插入,單次 \(\log\),一共執行 \(O(q)\) 個合併,單次 \(\log ^2\)

但是更一般地我們採用字首線性基做即可。

無力迴天NOI2017

線性基不支援整體標記,所以我們需要找某些手段將區間修改變成單點修改。

不妨\(b_i=a_i\oplus a_{i-1}\),每次就變成了單點修改

至於區間 \(a_l,a_{l+1}\dots,a_r\) 的線性基,等價於 \(a_l,b_{l+1},b_{l+2}\dots b_r\) 的線性基,這是顯然的(線性組合)。

那麼就可以線段樹暴力維護 \(O(n\log ^3 n)\)

CF959F

線性基性質的擴充套件。

\(n\) 個元素構成的線性基 \(B\),其任意元素 \(x\in \operatorname{span}(B)\)\(n\) 個元素裡,都恰有 \(2^{n-|B|}\) 個子序列 \(xor\) 和為 \(x\)

證明:

我們知道,線性基每個元素是由某些元素異或得到,不妨將其也表達為一個向量(出現/不出現)

插入時,會判斷 \(|B|\) 個線性基量是否選擇,就會被這些線性基元素表達的向量得到一個表達集合。

考慮到有 \(n-|B|\) 個元素插入失敗,他們其實相當於是提供了等效集合的可行性,每個都是選或者可以不選(選上後線性基可以再選一些讓其 \(xor\) 和為零),不影響答案

所以就是 \(2^{n-|B|}\)

CF938G

相當於每條邊有存在時間,考慮可撤銷帶權並查集維護線段樹分治,維護當前情況的線性基。

每走到一個節點時,儲存當前的線性基用來撤銷,這部分總 \(\log^2\)

總插入複雜度是 \(\log^2 n\)

插入邊時,如果不連通,那麼利用帶權並查集也可以求出新邊邊權,如果連通那麼成環,將其值插入線性基。

而總查詢複雜度是 \(\log\) 的。

所以總複雜度 \(\log^2\) 的。

CF388D

本質上是求有多少個本質不同的線性基滿足其最大異或值不超過 \(n\)

考慮我們只計數標準型線性基保證不重不漏

那麼設 \(f_{i,j,0/1}\) 表示 \(\ge i\) 的位已經填完,當前線性基已經在前面欽定了 \(j\) 個有值的元素,當前這一位如果再加上 \(2^i\) 能否大於 \(n\)​。

將線性基元素 \(<i\) 的位的取值延遲決策是很有意義的。

有如下限制:如果當前位作為某個線性基的最高位,那麼這一列僅有這個有值。

轉移考慮分類討論:

  1. 當前不填

    基本轉移:\(f_{i,j,0}·2^j\to f_{i-1,j,0}\)

    1. \(n\) 該位為 \(0\)

      \(f_{i,j,1}·2^{\max(0,j-1)}\to f_{i-1,j,1}\),這是已經填過的線性基全部異或起來這一位取零,所以有 \(2^{\max(0,j-1)}\) 種方法

    2. \(n\) 該位為 \(1\)

      \(f_{i,j,1}·2^{\max(0,j-1)}\to f_{i-1,j,0}\)

      \(f_{i,j,1}·2^{\max(0,j-1)}\to f_{i-1,j,1}\)

      對應一個取奇數個 \(1\),一個取偶數個 \(1\)\(f\) 能否繼續頂住上界。

  2. 當前要填

    基本轉移:\(f_{i,j,0}\to f_{i-1,j+1,0}\),這時候相當於該列全是零。

    1. \(n\) 該位為零,算了
    2. \(n\) 該位為 \(1\),有 \(f_{i,j,1}\to f_{i-1,j+1,1}\)

CF1299D

先斷開所有與 \(1\) 相連的邊,那麼說明每個連通塊至多有 \(2\) 條邊與 \(1\) 相連。

注意到值域很小,本質不同的線性基只有 \(374\)​ 個,可以直接暴力預處理出來,並將其作為狀態。

這相當於是求在所有連邊方案裡有多少個,拿出所有環異或值,異或不出 \(0\) 的方案數。

\(f_{i,j}\) 為處理完前 \(i\) 個連通塊,當前線性基狀態是 \(j\),預處理 \(trans_{j,k}\) 表示 \(j,k\) 兩個線性基合併後如果合法的後繼狀態。

可以分討:

  1. 該連通塊內部環可以表出 \(0\),則必須全部斷掉
  2. 只向這個連通塊連一條邊,仍然合法
  3. 向這個連通塊連兩條(如果存在),會產生新環,如果仍然合法,也可以加入 dp 轉移。

八縱八橫

注意到原圖連通,因此可以先求出 dfs 樹,然後將所有樹上的簡單環的異或值插入線性基
接著操作1,2都等價於動態加入/刪除某個值
然後問最大 xor 值。

離線下來直接帶刪 bitset 即可。

相關文章