线性基
线性基
线性基可以理解为:用尽量少的一组数,表示原集合所有“子集异或和”。
1. 核心思想
把一个整数看成二进制向量,例如:
3 = 011
5 = 101
6 = 110
异或相当于二进制向量的“加法”:
3 ^ 5 = 6
所以 {3, 5, 6} 里,6 是多余的,因为它能由 3 ^ 5 表示。
线性基会保留 {3, 5},丢掉 6。
2. 线性基维护什么
令 b[i] 表示:最高位是第 i 位的一个基向量。
插入一个数 x 时,从高位往低位消元:
若 x 的第 i 位是 0,跳过;
若 b[i] 不存在,把 x 放进 b[i];
若 b[i] 存在,令 x ^= b[i],消掉这一位;
最后若 x == 0,说明它可以由已有基表示,是冗余数。
例如插入 3, 5, 6:
3 = 011 -> b[1] = 3
5 = 101 -> b[2] = 5
6 = 110
6 ^ 5 = 011
3 ^ 3 = 000 -> 6 冗余
常用模板
#include <bits/stdc++.h>
using namespace std;
struct LinearBasis {
static constexpr int LOG = 62; // long long 最高到 62 位
long long b[LOG + 1]{};
// 插入一个数
bool insert(long long x) {
for (int i = LOG; i >= 0; --i) {
if (((x >> i) & 1LL) == 0) continue;
if (!b[i]) {
b[i] = x;
return true; // 插入成功,线性基维数 +1
}
x ^= b[i];
}
return false; // x 可由已有基表示
}
// 所有子集异或和中的最大值
long long getMax() const {
long long ans = 0;
for (int i = LOG; i >= 0; --i) {
if ((ans ^ b[i]) > ans) {
ans ^= b[i];
}
}
return ans;
}
// 判断 x 能否由原集合某些数异或得到
bool canRepresent(long long x) const {
for (int i = LOG; i >= 0; --i) {
if (((x >> i) & 1LL) == 0) continue;
if (!b[i]) return false;
x ^= b[i];
}
return true;
}
};
int main() {
LinearBasis lb;
lb.insert(3);
lb.insert(5);
lb.insert(6);
cout << lb.getMax() << '\n'; // 6
cout << lb.canRepresent(6) << '\n'; // 1
cout << lb.canRepresent(7) << '\n'; // 0
}
4. 它能解决什么题
题目描述 线性基操作
选若干数,使异或和最大 getMax()
某个值能否由若干数异或得到 canRepresent(x)
求不同子集异或和数量 若秩为 rank,数量是 2^rank
多组数合并 把一个线性基里的每个 b[i] 插入另一个
第 k 小 / 第 k 大子集异或和 需要把线性基进一步化为简化行阶梯形
复杂度很低:一次插入、查询都是 O(LOG),对 long long 来说约 O(63)。

浙公网安备 33010602011771号