1、线性基:一组线性无关的向量作为基底,张起一个线性的向量空间。这个基底称为线性基。线性基的基底通过线性运算,可以表示向量空间内的所有向量。
2、线性相关:在向量空间V的一组向量A:如果存在不全为零的数 k1, k2, ···,km , 使
则称向量组A是线性相关的,否则数 k1, k2, ···,km全为0时,称它是线性无关。
简单的说,线性相关就是其中一个向量能够被其他向量表示出来,不能表示出来就是线性无关。
3、设数集T的值域范围为[1,2n−1]。
T的线性基是T的一个子集A={a1,a2,a3,…,an}
A中元素互相xor所形成的异或集合,等价于原数集T的元素互相xor形成的异或集合。
4、性质
1、线性基的异或集合中不存在0,等价于每个元素的异或方案唯一
2、线性基二进制最高位1的位置互不相同,最高位的1唯一,且base[i]就是最高位(第i位)为1的唯一向量,
3、如果线性基是满的,它的异或集合为[1,2n−1]
4、线性基中元素互相异或,异或集合不变。即,任取向量组中两个向量a、b,把其中一个替换成a xor b,这组向量线性组合得到的线性空间相同
1、插入
从高位到低位扫描x二进制中的1,如果扫到第i位,此时的base[i]为0(不存在),把x作为向量,加入线性基并结束。如果存在了,让x异或base[i],把x第i位的1消去。对于新得到的x,继续往低位扫,取高位的1,重复操作。
这样就得到了性质:最高位1的位置互不相同(相同的都被抵消了,不存在才会加上去)
bool Insert(ll x)
{
for(int i=32;i>=0;--i)
{
if(x&(1ll<<i))
{
if(!base[i])
{
base[i]=x;
break;
}
x^=base[i];
}
}
return x>0;
}
2、合并
将一个线性基暴力插入另一个线性基即可
LinearBase Merge(const LinearBase &a,const LinearBase &b)
{
LinearBase ret=a;
for(int i=60;i>=0;--i)
if(b.base[i])
ret.Insert(b.base[i]);
return ret;
}
3、查询是否存在x
方法一:从高位往低位扫描x,如果x的第i位为1,但不存在向量d[ i ] ,这样便不可能将x异或为0,也就是不存在这样的x。否则x就异或d[i],如果到最后x变为0,则空间中存在这样的x
方法二:把它尝试插入进线性基里面去,假如可以插入,说明不能异或得到,假如插不进去,说明不能异或得到
bool find(ll x)
{
for(int i=32;i>=0;--i)
{
if(x&(1ll<<i))
{
if(!base[i])
break;
x^=base[i];
}
}
return x==0;
}
4、查询最大
从高位到低位扫描线性基。如果异或后可以使得答案变大,就异或到答案中去
ll QueryMax()
{
ll ret=0;
for(int i=60;i>=0;--i)
if((ret^base[i])>ret)
ret^=base[i];
return ret;
}
5、查询最小
最低位的向量,就是最小值
ll QueryMin()
{
for(int i=0;i<=60;++i)
if(base[i])
return base[i];
return 0;
}
6、查找第k小的值
首先对线性基进行改造,改造的结果是:一个向量二进制中最高位的1只出现在自己身上,其余向量在该位置都为0。比如,23:10111,15:1111,1:1,在改造完之后,变成了22:10110,15:1110,1:1
改造方法:从大到小枚举每一个线性基d[i],从它的第二高位往低位扫,如果扫到d[i]在第j位是1,那么就异或上d[j](d[j]最高位是1),这样就消去d[i]在第j位上的1。当然d[ j ]这个向量可能不存在。那么原本该位的1不变。当线性基饱和后,能异或出 1-2^n 中的任意一个数 。
所以查询的时候将k二进制拆分,对于1的位,就异或上对应的线性基。 最终得出的答案就是第k小的值。
注意判断0的情况, 也就是原序列有可能异或出0的情况来, 而这个线性基是判断不了的, 所以我们要人为判断, 那怎么判断了, 实际上就是如果插入到线性基中的数不是全体的数, 那么必定有零的这个元素的出现。想想插入的过程就懂了, 如果有零, 那么还需要k – 之后,再进行判断。
如果线性基的大小和原数组一样,0是不能被异或出来的,否则可以。
注意long long,判断无解的时候 要写成1ll,即k>=(1ll<<cnt)
void Rebuild()
{
for(int i=32;i>=0;i--)
for(int j=i-1;j>=0;j--)
if(base[i]&(1ll<<j))
base[i]^=base[j];
for(int i=0;i<=32;++i)
if(base[i])
p[cnt++]=base[i];
}
ll KthQuery(ll k)
{
ll ret=0;
if(k>=(1ll<<cnt))
return -1;
for(int i=60;i>=0;i--)
if(k&(1ll<<i))
ret^=p[i];
return ret;
}
板子
struct LinearBase
{
ll base[35],p[35];
int cnt;
LinearBase()
{
memset(base,0,sizeof(base));
memset(p,0,sizeof(p));
cnt=0;
}
bool Insert(ll x)
{
for(int i=32;i>=0;--i)
{
if(x&(1ll<<i))
{
if(!base[i])
{
base[i]=x;
break;
}
x^=base[i];
}
}
return x>0;
}
LinearBase Merge(const LinearBase &a,const LinearBase &b)
{
LinearBase ret=a;
for(int i=60;i>=0;--i)
if(b.base[i])
ret.Insert(b.base[i]);
return ret;
}
ll QueryMax()
{
ll ret=0;
for(int i=60;i>=0;--i)
if((ret^base[i])>ret)
ret^=base[i];
return ret;
}
ll QueryMin()
{
for(int i=0;i<=60;++i)
if(base[i])
return base[i];
return 0;
}
void Rebuild()
{
for(int i=32;i>=0;i--)
for(int j=i-1;j>=0;j--)
if(base[i]&(1ll<<j))
base[i]^=base[j];
for(int i=0;i<=32;++i)
if(base[i])
p[cnt++]=base[i];
}
bool find(ll x)
{
for(int i=32;i>=0;--i)
{
if(x&(1ll<<i))
{
if(!base[i])
break;
x^=base[i];
}
}
return x==0;
}
};
LinearBase Intersection(LinearBase A,LinearBase B)
{
LinearBase All,C,D;
for (int i=32;i>=0;i--)
All.base[i] = A.base[i];
for (int i=32;i>=0;i--)
if(B.base[i])
{
ll v=B.base[i],k=1ll<<i;
bool can = true;
for (int j=32;j>=0;j--)
{
if (v&(1ll<<j))
{
if (All.base[j])
{
v^=All.base[j];
k^=D.base[j];
}
else
{
can = false;
All.base[j]=v;
D.base[j]=k;
break;
}
}
}
if (can)
{
ll v=0;
for(int j=32;j>=0;j--)
if(k&(1ll<<j))
v^=B.base[j];
C.Insert(v);
}
}
C.Rebuild();
return C;
}
2019牛客暑期多校训练营(第四场)B xor
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d) (abs(d) < 1e-8)
using namespace std;
const int maxn=5e4+5,INF=0x3f3f3f3f;
const int mod=1e9+7;
struct LinearBase
{
ll base[35],p[35];
int cnt;
LinearBase()
{
memset(base,0,sizeof(base));
memset(p,0,sizeof(p));
cnt=0;
}
bool Insert(ll x)
{
for(int i=32;i>=0;--i)
{
if(x&(1ll<<i))
{
if(!base[i])
{
base[i]=x;
break;
}
x^=base[i];
}
}
return x>0;
}
void Rebuild()
{
for(int i=32;i>=0;i--)
for(int j=i-1;j>=0;j--)
if(base[i]&(1ll<<j))
base[i]^=base[j];
for(int i=0;i<=32;++i)
if(base[i])
p[cnt++]=base[i];
}
bool find(ll x)
{
for(int i=32;i>=0;--i)
{
if(x&(1ll<<i))
{
if(!base[i])
break;
x^=base[i];
}
}
return x==0;
}
};
LinearBase Intersection(LinearBase A,LinearBase B)
{
LinearBase All,C,D;
for (int i=32;i>=0;i--)
All.base[i] = A.base[i];
for (int i=32;i>=0;i--)
if(B.base[i])
{
ll v=B.base[i],k=1ll<<i;
bool can = true;
for (int j=32;j>=0;j--)
{
if (v&(1ll<<j))
{
if (All.base[j])
{
v^=All.base[j];
k^=D.base[j];
}
else
{
can = false;
All.base[j]=v;
D.base[j]=k;
break;
}
}
}
if (can)
{
ll v=0;
for(int j=32;j>=0;j--)
if(k&(1ll<<j))
v^=B.base[j];
C.Insert(v);
}
}
C.Rebuild();
return C;
}
int n,m;
LinearBase lb[maxn],ST[maxn<<2];
void Push_up(int rt)
{
ST[rt]=Intersection(ST[ls],ST[rs]);
}
void Build(int rt,int L,int R)
{
if(L==R)
{
ST[rt]=lb[L];
return;
}
int mid=(L+R)>>1;
Build(ls,L,mid);
Build(rs,mid+1,R);
Push_up(rt);
}
bool Query(int rt,int l,int r,int L,int R,ll x)
{
if(l<=L&&R<=r)
return ST[rt].find(x);
int mid=(L+R)>>1;
bool ret1=true,ret2=true;
if(l<=mid)
ret1=Query(ls,l,r,L,mid,x);
if(r>mid)
ret2=Query(rs,l,r,mid+1,R,x);
return ret1&&ret2;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;++i)
{
int x;
ll y;
scanf("%d",&x);
for(int j=1;j<=x;++j)
{
scanf("%lld",&y);
lb[i].Insert(y);
}
}
Build(1,1,n);
ll l,r,x;
while(m--)
{
scanf("%lld %lld %lld",&l,&r,&x);
bool result=Query(1,l,r,1,n,x);
if(result)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}