UOJ #91. 【集訓隊互測2015】最大異或和
阿新 • • 發佈:2022-05-18
題目大意
給出一個長為 \(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; }