线性基学习笔记
线性相关
对于一个集合 $S$ 如果存在一个元素 $s'$ 使得 $S$ 在去除这个元素后仍能通过剩余元素表示出该元素,就说 $S$ 是线性相关的,反之为线性无关。
线性基
我们称集合 $B$ 是一个集合 $S$ 的线性基,当且仅当:  
- $S \subseteq span(B)$
- $B$ 是线性无关的。
据此我们可以推出线性基的性质:
- $B$ 的任何真子集都不为 $S$ 的线性基。
- $S$ 中的任一元素都可以唯一被 $B$ 中元素表示出来。
给出一个异或线性基的构造方法:
假设 $L$ 为 $S$ 中的最大元素二进制下的位数,我们用一个 $\left[ 0,L-1  \right ]$ 位的数组表示线性基。 设当前要插入的数为 $x$ ,从高位开始考虑,设考虑到第 $y$ 位。  
- 若 $x \oplus 2^y = 0$ 则跳过
- 若第 $y$ 已经插入了数,则 $x \gets x \oplus a_y$
- 若第 $y$ 位为空,$a_{y'} \gets x \oplus a_{y'}$ ,$y' \in [0,y-1]$,然后再插入 $x$
正确性:考虑贪心,因为第 $y$ 位是 $1$ 的贡献比小于 $y$ 的所有位都为 $1$ 的贡献更大,所以能选高位就选高位。下面两种写法都基于这个贪心,不同的是一种写法是在插入时处理,另一种是在计算答案时处理。
线性基两种写法
$FIRST$
void insert(long long x) {
    int i = N;
    long long L = 1ll << i; 
    for(;L;L >>= 1, i--) {
        if(! (x & L)) continue;
        if(a[i]) x ^= a[i];
        else {
            for(int j = 0;j < i;j++) if(x & (1ll << j)) x ^= a[j];
            for(int j = i + 1;j <= N;j++) if(a[j] & L) a[j] ^= x;
            a[i] = x;
            return;
        }
    }
}
long long sum() {
    long long ans = 0;
    for(int i = 0;i <= N + 1;i++) ans ^= a[i];
    return ans;
}$SECOND$
void insert(long long x)
{
    int i = N;
    long long L = 1ll << N;
    for (; L; L >>= 1, i--)
        if ((x & L))
        {
            if (a[i]) x ^= a[i];
            else
            {
                a[i] = x;
                return;
            }
        }
}
long long sum()
{
    long long ans = 0;
    for (int i = N + 1; i >= 0; i--)
    {
        if (ans & (1ll << i)) continue;
        else ans ^= a[i];
    }
    return ans;
} 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号