线性基学习笔记
线性相关
对于一个集合 $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号