转自https://www.luogu.org/blog/Marser/solution-p3812
首先,线性基是用于查询多个数中选取一些数的Xor最大值,最小值,以及能否得到某个值的数据结构,可以在log的时间内解决问题。
它实际上是一个大小为log的数组,对于每一位记录一个最高位为它的某个数,要求这个数组可以表示所有这些数的子集的Xor值,初始全部为零。
插入和判断
插入数u时,从高位到低位遍历,如果u的这一位有值,则进行判断,若数组的这一位还没有数,则改为u并且break,否则u^数组中的这个数(详见代码),这样操作之后u只有两种结果:
-
被记录到了数组中
-
未被记录,则此时u必定为0,说明此时的线性基已经能通过Xor得到u.
因此我们可以用这种方法来判断此时是否存在Xor值为u的子集.
void ins(long long x){
for(int i=maxlog;i>=0;i--)
if(x&(1ll<<i))
if(!a[i]){a[i]=x;return;}
else x^=a[i];
}
bool check(long long x){
for(int i=maxlog;i>=0;i--)
if(x&(1ll<<i))
if(!a[i])return 0;
else u^=a[i];
return 1;
}
查询最值
最大值可以用贪心的思想来做。
从高到低遍历数组,如果ans^第i位的那个数后大于ans,则^这个数,因为这样可以保证ans第i位为1,且后面不可能有机会改变第i位。
很显然,数组中最小的非零数就是最小值。
查询第k小值
首先将数组中的所有数变成包含这个最高位且可以通过Xor得到的最小值。
具体实现方法就是每一位向后扫,若Xor后变小,则Xor。
之后就可以发现第k小只要将k改为二进制后,将二进制所对应的位置的数Xor起来即可。
long long qmax(){
long long res=0;
for(int i=maxlog;i>=0;i--)if((res^a[i])>res)res^=a[i];
return res;
}
long long qmin(){
for(int i=0;i<=maxlog;i++)if(a[i])return a[i];
}
long long query(int k){
long long tmp[maxlog+1],res=0;int cnt=0;
for(int i=0;i<=maxlog;i++){
for(int j=i-1;j>=0;j--)if(a[i]&(1ll<<j))a[i]^=a[j];
if(a[i])tmp[cnt++]=a[i];
}
for(int i=0;i<cnt;i++)if(k&(1ll<<i))res^=tmp[i];
return res;
}
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
template<typename T>struct linear_base{
static const int maxlog=60;
T a[61];
void ins(T x){
for(T i=maxlog;i>=0;i--)
if(x&((T)(1)<<i))
if(!a[i]){a[i]=x;return;}
else x^=a[i];
}
bool check(T x){
for(T i=maxlog;i>=0;i--)
if(x&((T)(1)<<i))
if(!a[i])return 0;
else x^=a[i];
return 1;
}
T qmax(){
T res=0;
for(T i=maxlog;i>=0;i--)if((res^a[i])>res)res^=a[i];
return res;
}
T qmin(){
for(T i=0;i<=maxlog;i++)if(a[i])return a[i];
}
T query(int k){
T tmp[maxlog+1],res=0,cnt=0;
for(T i=0;i<=maxlog;i++){
for(int j=i-1;j>=0;j--)if(a[i]&((T)(1)<<j))a[i]^=a[j];
if(a[i])tmp[cnt++]=a[i];
}
for(T i=0;i<cnt;i++)if(k&((T)(1)<<i))res^=tmp[i];
return res;
}
};
linear_base<ll>s;
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){ll x;scanf("%lld",&x);s.ins(x);}
printf("%lld\n",s.qmax());
return 0;
}