【数据结构】线性基

参考题:https://www.luogu.com.cn/problem/P3812

作用

  • 查询某个数是否能被一组数异或得到
  • 查询一组数能够异或的到的最大/小值,第k大值

解释

本质上就是作用在 \(01\) 串的高斯消元,只不过消元的途径是异或

比如一组数(二进制):

1010

1100

0011

建立线性基的过程是:
\(\begin{pmatrix} 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ \end{pmatrix}\)

对第一个数:
从最高位开始扫,发现第一位就是 \(0\) ,故更新:

\(\begin{pmatrix} 1 & 0 & 1 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ \end{pmatrix}\)

对第二个数:
依然从最高位开始扫,发现第一位是 \(1\) ,所以第二个数要异或第一位对应的基底得到 \(0110_{(2)}\) ,继续扫,第二位是\(0\),故更新为:

\(\begin{pmatrix} 1 & 0 & 1 & 0\\ 0 & 1 & 1 & 0\\ 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0\\ \end{pmatrix}\)

类似的,对第三个数,可以更新矩阵得到:

\(\begin{pmatrix} 1 & 0 & 1 & 0\\ 0 & 1 & 1 & 0\\ 0 & 0 & 1 & 1\\ 0 & 0 & 0 & 0\\ \end{pmatrix}\)

可以发现上面整个过程就是通过异或来进行高斯消元

代码:

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N=55;

ll base[N];

int main(){
    int n; cin>>n;
    while(n--){
        ll k; cin>>k;
        for(int j=N-1;~j;j--){
            if(k&(1LL<<j)){
                if(!base[j]) base[j]=k;
                k^=base[j];
            }
        }
    }

    ll ans=0;
    for(int j=N-1;~j;j--){
        if((ans^base[j])>ans) ans=ans^base[j];
    }

    cout<<ans<<endl;

    return 0;
}
posted @ 2021-02-18 10:50  HinanawiTenshi  阅读(84)  评论(0编辑  收藏  举报