线性基
线性基
1、三大性质:
- 原序列里面的任意一个数都可以由线性基里面的一些数异或所得到
- 线性基里面的任意一些数异或起来都不可能得到 \(0\)
- 线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的
2、构造 \(p\) 数组:每次我们插入一个数 \(x\) 时,如果 \(x\) 二进制的第 \(i\) 为 \(1\),且 \(d[i]==0\),则表示此位还没有存入数字进去,则在第 \(i\) 位插入数字 \(x\);否则,则让 \(x=x\ xor\ d[i]\),继续往低位遍历。
struct Basis{
static const int N = 60;
i64 p[N + 1], p_[N + 1];
i64 tot;
bool is_0;
Basis() {
memset(p, 0, sizeof p);
memset(p_, 0, sizeof p_);
is_0 = 0;
tot = 0;
}
inline void add(i64 x) {// 添加某个数进去
for (i64 i = N; i >= 0; i--) {
if (x >> i & 1) {
// 如果这位之前已经被其他数所占用了,那就不能将这个数加进去,只能继续往低位找
if (p[i]) {
x ^= p[i];
} else {
tot++;
p[i] = x;
break;
}
}
}
if (x == 0) is_0 = 1;
}
inline bool is(i64 x) {
// 判断这个数是否存在
if (!x) {
// 0需要直接特判是否存在
if (is_0) return true;
return false;
}
for (i64 i = N; i >= 0; i--) {
if (x >> i & 1) {
if (!p[i]) return false;
x ^= p[i];
}
}
return true;
}
inline i64 get_max() {// 得到这个这个线性基内任意取数异或所产生的最大值
i64 ans = 0;
for (i64 i = N; i >= 0; i--) {
ans = max(ans, ans ^ p[i]);
}
return ans;
}
inline i64 get_min() {// 得到这个这个线性基内任意取数异或所产生的最小值
if (is_0) return 0LL;
for (i64 i = 0; i <= N; i++) {
if (p[i]) return p[i];
}
}
inline void work() {// 预处理
for (i64 i = 0; i <= N; i++) p_[i] = p[i];
for (i64 i = 1; i <= N; i++) {
for (i64 j = 0; j < i; j++) {
if (p_[i] >> j & 1) {
p_[i] ^= p_[j];
}
}
}
}
// 求序列中选取任意数的第k小的数
inline i64 kth_min(i64 k) {
i64 total = 1LL << tot;
if (k == 1 && is_0) return 0;
if (is_0) k--, total--;
if (k > total) {// 表示序列没有超过k个不同的异或和值
return -1;
}
work();
i64 ans = 0;
for (i64 i = 0; i <= N; i++) {
if (p_[i]) {
if (k & 1) ans ^= p_[i];
k >>= 1LL;
}
}
return ans;
}
// 求序列中选取任意数的第k大的数
inline i64 kth_max(i64 k) {
i64 tal = 1LL << tot;
if (!is_0) tal--;
k = tal - k + 1;
if (k <= 0) {
return -1;
}
return kth_min(k);
}
};
3、模版一:洛谷P3812。
void solve() {
int n;
cin >> n;
vector<i64> a(n + 1);
Basis t;
for (int i = 1; i <= n; i++) {
cin >> a[i];
t.add(a[i]);
}
cout << t.get_max() << '\n';
}
4、模版二:loj。
void solve() {
int n;
cin >> n;
vector<i64> a(n + 1);
Basis t;
for (int i = 1; i <= n; i++) {
cin >> a[i];
t.add(a[i]);
}
int m;
cin >> m;
for (int i = 1; i <= m; i++) {
i64 k;
cin >> k;
cout << t.kth_min(k) << '\n';
}
}

浙公网安备 33010602011771号