1. 程式人生 > 其它 >UOJ #91. 【集訓隊互測2015】最大異或和

UOJ #91. 【集訓隊互測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\) 與基底,並繼續插入的流程。

程式碼

#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;
}