[UOJ91] [集训队互测2015] 最大异或和

题目大意

给出一个长为 \(n\) 的序列,要求实现三种操作,分别为区间异或上某数,区间覆盖为某数,和询问全局选出若干个数能获得的最大异或和。所有出现的数均不超过 $ 2^m $,操作数不超过 \(q\)\(n,m,q\leq 2000\)

分析题意

观察到询问操作所需的就是维护序列的线性基。注意到对于线性基中的两个数 \(x,y\),如果将 \(x\) 变为 \(x\oplus y\),则线性基所能构成的数的集合不变。于是考虑维护差分序列的线性基,修改操作变为修改线性基中的某个元素,和从线性基中删除差分序列的一个区间。删除操作可以暴力删除,因为插入线性基的数总个数是 \(O(n+q)\) 量级的。于是修改操作又转化为维护支持插入一个数和删除一个数的线性基。

带删线性基

题目并没有要求强制在线,所以可以离线并记录下每个插入的元素的删除时间。对于插入的某个元素 \(x\),它会异或上当前线性基基底的若干个数。如果线性基基底所对应的元素先于 \(x\) 删除,就不得不消去基底对 \(x\) 的影响,因而十分麻烦;反之,则直接删去 \(x\) 即可。于是,当 \(x\) 的删除时间晚于它将要异或上的基底时,不妨直接交换 \(x\) 与基底,并继续插入的流程。

时间复杂度

\(O(\dfrac{(n+m)\times m\times q}{\omega})\),瓶颈在于修改操作的转化和线性基的插入。

代码

#include <bits/stdc++.h>
using namespace std;
constexpr int MAXN = 2010;
int n, m, Q, last[MAXN];
bitset<MAXN> a[MAXN], b[MAXN];
pair<bitset<MAXN>, int> bs[MAXN];
vector<pair<bitset<MAXN>, int>> vec[MAXN];
struct query {
    int opt, l, r;
    bitset<MAXN> w;
} q[MAXN];
void insert(pair<bitset<MAXN>, int> cur) {
    for (int i = m - 1; i >= 0; --i) {
        if (!cur.first.test(i)) continue;
        if (bs[i].second == -1) {
            bs[i] = cur;
            break;
        } else {
            if (bs[i].second < cur.second) swap(cur, bs[i]);
            cur.first ^= bs[i].first;
        }
    }
}
bitset<MAXN> ask() {
    bitset<MAXN> ret;
    for (int i = m - 1; i >= 0; --i) {
        if (!ret.test(i) && bs[i].second != -1)
            ret ^= bs[i].first;
    }
    return ret;
}
void print(const bitset<MAXN> &x) {
    for (int i = m - 1; i >= 0; --i) cout << x.test(i);
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n >> m >> Q;
    for (int i = 1; i <= n; ++i) cin >> a[i], b[i] = a[i] ^ a[i - 1];
    for (int i = 1; i <= Q; ++i) {
        cin >> q[i].opt;
        if (q[i].opt == 1) {
            cin >> q[i].l >> q[i].r >> q[i].w;
            for (int j = q[i].l; j <= q[i].r; ++j) a[j] ^= q[i].w;
        } else if (q[i].opt == 2) {
            cin >> q[i].l >> q[i].r >> q[i].w;
            for (int j = q[i].l; j <= q[i].r; ++j) a[j] = q[i].w;
        }
        if (q[i].opt <= 2) {
            for (int j = q[i].l; j <= min(q[i].r + 1, n); ++j) {
                bitset<MAXN> tmp = a[j] ^ a[j - 1];
                if (tmp != b[j]) {
                    if (b[j].any()) vec[last[j]].emplace_back(b[j], i);
                    b[j] = tmp, last[j] = i;
                }
            }
        }
    }
    for (int i = 1; i <= n; ++i) if (b[i].any()) vec[last[i]].emplace_back(b[i], Q + 1);
    for (int i = 0; i < m; ++i) bs[i].second = -1;
    for (int i = 0; i <= Q; ++i) {
        for (int j = 0; j < m; ++j) if (bs[j].second == i) bs[j].second = -1;
        for (auto &j : vec[i]) insert(j);
        if (q[i].opt == 3) print(ask()), cout << "\n";
    }
    return 0;
}
posted @ 2022-05-18 19:18  JCY_std  阅读(196)  评论(0编辑  收藏  举报