[UOJ91]最大异或和
可删除线性基。
有一个数列 \(a_1,a_2,\dots,a_n\),每个 \(a_i\) 都是小于 \(2^m\) 的非负整数。
现在需要实现三种操作,格式说明如下:
- 1 x y w:对于所有 \(x≤i≤y\),将 \(a_i\) 修改为 \(a_i\oplus w\)。其中 \(w\) 是一个小于 \(2^m\) 的非负整数。
- 2 x y w:对于所有 \(x≤i≤y\),将 \(a_i\) 修改为 \(w\)。其中 \(w\) 是一个小于 \(2^m\) 的非负整数。
- 3:从 \(a_1,a_2,⋯,a_n\) 中选出若干个数,使得选出的数异或和最大。请输出这个最大值。
这里 \(\oplus\) 表示按位异或运算,\(x_1,x_2,⋯,x_l\) 的异或和是指 \(x_1\oplus x_2\oplus \cdots\oplus x_l\)。
\(n,m,q≤2000\)。
将原序列差分,线性基不变。
然后每次操作就是单点插入和删除,下面给出两种可删除线性基的写法。
离线
记录存活时间,贪心。
using BS = std::bitset<2000>;
using PBI = std::pair<BS, int>;
[2000];
PBI basevoid ins(PBI x) {
for (int i = 1999; i >= 0; i--) {
if (!x.first[i]) continue;
if (x.second > base[i].second) {
std::swap(x, base[i]);
if (!x.second) break;
}
.first ^= base[i].first;
x}
}
在线
\[ PV=B \]
\[ \det(P)\neq 0, V = \begin{pmatrix} v_1\\ v_2\\ \vdots\\ v_n \end{pmatrix}, B= \begin{pmatrix} base_1\\ \vdots\\ 0\\ \vdots\\ base_m\\ \vdots\\ 0\\ \vdots \end{pmatrix} \]
记录可逆矩阵 \(P\),修改 \(v_i\) 时,要将 \(P\) 的第 \(i\) 列全部变成0。
为了尽量在不影响 \(B\) 的情况下消元,首先找 \(j\) 满足 \(P_{i,j}=1,i\neq j, base_j=0\)。
如果找到这样的 \(j\) 那么直接消元,\(B\) 不会有任何变化。
如果没有找到,那么需要找最小的 \(base_k\) 使得 \(base_k\) 包含 \(v_i\),然后用 \(base_k\) 消去其他包含 \(v_i\) 的 \(base\)。
Code
离线
// Author: HolyK
// Created: Mon Jul 5 14:24:21 2021
#include <bits/stdc++.h>
#define dbg(a...) fprintf(stderr, a)
template <class T, class U>
inline bool smin(T &x, const U &y) {
return y < x ? x = y, 1 : 0;
}
template <class T, class U>
inline bool smax(T &x, const U &y) {
return x < y ? x = y, 1 : 0;
}
using LL = long long;
using PII = std::pair<int, int>;
using BS = std::bitset<2000>;
using PBI = std::pair<BS, int>;
int n, m, q;
[2000];
PBI basevoid ins(PBI x) {
for (int i = m - 1; i >= 0; i--) {
if (!x.first[i]) continue;
if (x.second > base[i].second) {
std::swap(x, base[i]);
if (!x.second) break;
}
.first ^= base[i].first;
x}
}
[2005];
BS astd::vector<PBI> g[2005];
int t[2005];
bool ask[2005];
char tmp[2005];
int main() {
("%d%d%d", &n, &m, &q);
scanffor (int i = 1; i <= n; i++) {
("%s", tmp);
scanffor (int j = 0; j < m; j++) a[i][j] = tmp[m - 1- j] ^ '0';
}
for (int i = 1; i <= q; i++) {
int opt;
("%d", &opt);
scanfif (opt == 3) {
[i] = true;
ask} else {
int x, y;
;
BS z("%d%d", &x, &y);
scanf("%s", tmp);
scanffor (int j = 0; j < m; j++) z[j] = tmp[m - 1- j] ^ '0';
++;
yif (opt == 1) {
if (t[x] != -1) g[t[x]].emplace_back(a[x] ^ a[x - 1], i - 1);
if (t[y] != -1) g[t[y]].emplace_back(a[y] ^ a[y - 1], i - 1);
for (int j = x; j < y; j++) a[j] ^= z;
[x] = t[y] = i;
t} else {
for (int j = x; j <= y && j <= n; j++) {
if (t[j] != -1) g[t[j]].emplace_back(a[j] ^ a[j - 1], i - 1);
[j] = -1;
t}
for (int j = x; j < y; j++) a[j] = z;
[x] = t[y] = i;
t}
}
}
for (int i = 1; i <= n; i++) if (t[i] != -1) g[t[i]].emplace_back(a[i] ^ a[i - 1], q);
for (int i = 0; i <= q; i++) {
for (auto &v : g[i]) ins(v);
if (!ask[i]) continue;
;
BS ansfor (int j = m - 1; j >= 0; j--) {
if (base[j].second >= i && !ans[j]) ans ^= base[j].first;
}
for (int j = m - 1; j >= 0; j--) putchar("01"[ans[j]]);
("");
puts}
return 0;
}
在线
// Author: HolyK
// Created: Mon Jul 5 15:29:33 2021
#include <bits/stdc++.h>
#define dbg(a...) fprintf(stderr, a)
template <class T, class U>
inline bool smin(T &x, const U &y) {
return y < x ? x = y, 1 : 0;
}
template <class T, class U>
inline bool smax(T &x, const U &y) {
return x < y ? x = y, 1 : 0;
}
using LL = long long;
using PII = std::pair<int, int>;
constexpr int N(2005);
using BS = std::bitset<N>;
int n, m, q;
int base[N];
[N], v[N], p[N];
BS avoid ins(int id) {
for (int i = m - 1; i >= 0; i--) {
if (!v[id][i]) continue;
if (!base[i]) {
[i] = id;
basereturn;
}
[id] ^= v[base[i]];
v[id] ^= p[base[i]];
p}
}
void update(int id, const BS &z) {
if (z.none()) return;
int j = 0;
for (int i = 1; i <= n; i++) {
if (v[i].any() || !p[i][id]) continue;
= i;
j break;
}
if (!j) {
for (int i = 0; i < m; i++) {
if (!base[i] || !p[base[i]][id]) continue;
= base[i];
j [i] = 0;
basebreak;
}
}
assert(j);
for (int i = 1; i <= n; i++) {
if (i == j || !p[i][id]) continue;
[i] ^= v[j];
v[i] ^= p[j];
p}
[j] ^= z;
v(j);
ins}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n >> m >> q;
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
[i] = a[i] ^ a[i - 1];
v[i].set(i);
p(i);
ins}
while (q--) {
int opt, x, y;
;
BS zstd::cin >> opt;
if (opt == 1) {
std::cin >> x >> y >> z;
(x, z);
updateif (y < n) update(y + 1, z);
for (int i = x; i <= y; i++) a[i] ^= z;
} else if (opt == 2) {
std::cin >> x >> y >> z;
(x, a[x] ^ z);
updateif (y < n) update(y + 1, a[y] ^ z);
for (int i = x; i < y; i++) update(i + 1, a[i] ^ a[i + 1]);
for (int i = x; i <= y; i++) a[i] = z;
} else {
.reset();
zfor (int i = m - 1; i >= 0; std::cout << z[i--]) {
if (base[i] && !z[i]) z ^= v[base[i]];
}
std::cout << "\n";
}
}
return 0;
}
最后修改于 2021-08-13