应用
线性基最基本的应用,就是子集最大异或和问题:
- 子集 kk 大异或和:HDU 3949
- 最大路径异或和:WC2011 Xor
- 求子集异或值排名:BZOJ 2844
- 树上两点间子集最大异或和:SCOI2016 幸运数字
【非显式构造】不显式构造出集合 BB,支持动态插入。
struct LinearBasis
{
long long a[MAXL + 1];
LinearBasis()
{
std::fill(a, a + MAXL + 1, 0);
}
LinearBasis(long long *x, int n)
{
build(x, n);
}
void insert(long long t)
{
for (int j = MAXL; j >= 0; j--)
{
if (!t) return;
if (!(t & (1ll << j))) continue;
if (a[j]) t ^= a[j];
else
{
for (int k = 0; k < j; k++) if (t & (1ll << k)) t ^= a[k];
for (int k = j + 1; k <= MAXL; k++) if (a[k] & (1ll << j)) a[k] ^= t;
a[j] = t;
break;
}
}
}
// 数组 x 表示集合 S,下标范围 [1...n]
void build(long long *x, int n)
{
std::fill(a, a + MAXL + 1, 0);
for (int i = 1; i <= n; i++)
{
insert(x[i]);
}
}
long long queryMax()
{
long long res = 0;
for (int i = 0; i <= MAXL; i++) res ^= a[i];
return res;
}
void mergeFrom(const LinearBasis &other)
{
for (int i = 0; i <= MAXL; i++) insert(other.a[i]);
}
static LinearBasis merge(const LinearBasis &a, const LinearBasis &b)
{
LinearBasis res = a;
for (int i = 0; i <= MAXL; i++) res.insert(b.a[i]);
return res;
}
};
【显式构造】显式构造出集合 BB(代码中的 vv),不支持动态插入
struct LinearBasis
{
std::vector<long long> v;
int n; // 原有集合 S 的大小
// 数组 x 表示集合 S,下标范围 [1...n]
void build(long long *x, int n)
{
this->n = n;
std::vector<long long> a(MAXL + 1);
for (int i = 1; i <= n; i++)
{
long long t = x[i];
for (int j = MAXL; j >= 0; j--)
{
if ((t & (1ll << j)) == 0) continue;
if (a[j]) t ^= a[j];
else
{
for (int k = 0; k < j; k++) if (t & (1ll << k)) t ^= a[k];
for (int k = j + 1; k <= MAXL; k++) if (a[k] & (1ll << j)) a[k] ^= t;
a[j] = t;
break;
}
}
}
v.clear();
for (int i = 0; i <= MAXL; i++) if (a[i]) v.push_back(a[i]);
}
long long queryMax()
{
long long x = 0;
for (size_t i = 0; i < v.size(); i++) x ^= v[i];
return x;
}
};