2017 ACM-ICPC Asia Xi'an Problem A XOR(异或线性基 )
题目链接 2017西安赛区 Problem A
题意 给定一个数列,和$q$个询问,每个询问中我们可以在区间$[L, R]$中选出一些数。
假设我们选出来的这个数列为$A[i_{1}]$, $A[i_{2}]$, ..., $A[i_{t}]$
求$K$ $or$ $($$A[i_{1}]$ $xor$ $A[i_{2}]$ ... $xor$ $A[i_{t}]$$)$的最大值
首先常规操作,每次在线段树上求出区间$[L, R]$代表的线性基。
然后把这个线性基中所有$K$的二进制表示为$1$的位全部削成$0$。
这样得到了新的不超过$30$个数,把新的这些数单独用一个线性基表示。
最后答案就是新的这个线性基中选出某些数能异或出来的最大值或上$K$的结果。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define ls i << 1 #define rs i << 1 | 1 #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R const int N = 1e4 + 10; const int all = (1 << 27) - 1; int n, q, k; int T; int a[N], cnt; struct lb{ int d[30]; void clear(){ memset(d, 0, sizeof d); cnt = 0; } bool ins(int val){ dec(i, 28, 0) if (val & (1 << i)){ if (!d[i]){ d[i] = val; break; } val ^= d[i]; } return val > 0; } int qmax(){ int ret = 0; dec(i, 28, 0) if ((k | (ret ^ d[i])) > (k | ret)) ret ^= d[i]; return k | ret; } }; lb t[N << 3], c; lb merge(const lb &n1, const lb &n2){ lb ret = n1; dec(i, 28, 0) if (n2.d[i]) ret.ins(n2.d[i]); return ret; } void build(int i, int L, int R){ if (L == R){ t[i].ins(a[L]); return; } int mid = (L + R) >> 1; build(lson); build(rson); t[i] = merge(t[ls], t[rs]); } lb query(int i, int L, int R, int l, int r){ if (L == l && R == r) return t[i]; int mid = (L + R) >> 1; if (r <= mid) return query(lson, l, r); else if (l > mid) return query(rson, l, r); else return merge(query(lson, l, mid), query(rson, mid + 1, r)); } int main(){ scanf("%d", &T); while (T--){ scanf("%d%d%d", &n, &q, &k); rep(i, 0, 4e4) t[i].clear(); rep(i, 1, n) scanf("%d", a + i); build(1, 1, n); while (q--){ int x, y; scanf("%d%d", &x, &y); lb now = query(1, 1, n, x, y); cnt = all ^ k; dec(i, 28, 0) now.d[i] &= cnt; c.clear(); dec(i, 28, 0) if (now.d[i]) c.ins(now.d[i]); printf("%d\n", c.qmax() | k); } } return 0; }