CodeForces - 1100F - Ivan and Burgers
题意
- 给定一个长度为n的数列. 然后有q次查询,查询[L, R]区间中的某个子集异或和最大。
思路
- 我们定义 p [ r ] [ i ] p[r][i] p[r][i]为 [ 1 , r ] [1, r] [1,r]的线性基,并且这个线性基区别于平常从左往右插入,这个是从右往左插。
- 于是我们查询 [ L , R ] [L, R] [L,R]某些向量异或和最大时,就可以完美避开前 [ 1 , L ) [1, L) [1,L)向量的影响。直接遍历线性基 p [ r ] p[r] p[r],如果插入向量的位置在 [ L , R ] [L, R] [L,R]范围内,那么就取异或最大咯~,否则直接舍掉
如何保证我们所取的向量在 [ L , R ] [L, R] [L,R]中呢?
- 这时候我们就需要另外一个数组 p o s [ r ] [ i ] pos[r][i] pos[r][i]表示 [ 1 , r ] [1, r] [1,r]区间满足上述“从右往左插入向量”条件的线性基向量的位置。
- 这个数组在我们构建前缀线性基时也有重要作用!!!首先我们无论是 p [ r ] p[r] p[r]还是 p o s [ r ] pos[r] pos[r]在开始的时候都需要继承 p [ r − 1 ] p[r-1] p[r−1]和 p o s [ r − 1 ] pos[r-1] pos[r−1]. 这里数组 p o s [ ] [ ] pos[ \ ][ \ ] pos[ ][ ]的作用就是更新当前线性基的 p [ r ] [ i ] p[r][i] p[r][i]为最靠右的向量。
插入向量的代码
void add(int x, int R)
{
int id = R;
for(int i = maxBit - 1; i >= 0; -- i ) p[R][i] = p[R - 1][i], pos[R][i] = pos[R - 1][i];
for(int i = maxBit - 1; i >= 0; -- i )
{
if(x >> i & 1)
{
if(!p[R][i]) { p[R][i] = x; pos[R][i] = id; break; }
if(pos[R][i] < id) { swap(p[R][i], x); swap(pos[R][i], id); }
x ^= p[R][i];
}
}
}
完整代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int read()
{
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') f = -f; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}
const int maxN = 500005;
const int maxBit = 21;
int n, c[maxN];
int p[maxN][maxBit];
int pos[maxN][maxBit];
void add(int x, int R)
{
int id = R;
for(int i = maxBit - 1; i >= 0; -- i ) p[R][i] = p[R - 1][i], pos[R][i] = pos[R - 1][i];
for(int i = maxBit - 1; i >= 0; -- i )
{
if(x >> i & 1)
{
if(!p[R][i]) { p[R][i] = x; pos[R][i] = id; break; }
if(pos[R][i] < id) { swap(p[R][i], x); swap(pos[R][i], id); }
x ^= p[R][i];
}
}
}
int main()
{
n = read();
for(int i = 1; i <= n; ++ i )
{
c[i] = read();
add(c[i], i);
}
int QAQ; QAQ = read();
while(QAQ -- )
{
int l, r; l = read(); r = read();
int ans = 0;
for(int i = maxBit - 1; i >= 0; -- i )
if(pos[r][i] >= l)
ans = max(ans, ans ^ p[r][i]);
cout << ans << endl;
}
return 0;
}