线性基
所以说这种神玩意我怎么可能自己研究嘛,都是搬运的,出处详见参考资料
1数学基础
1.1 向量空间 vector space
定义
(F,V,+,⋅)
为向量空间,其中
F
为域,
1.2线性无关 linearly independent
对于向量空间中
V
上
则称这 n 个向量 线性相关,否则称为 线性无关 。
1.3线性组合 linear combination
对于向量空间中
其中 a1,a2,…,an∈F
一组向量 线性无关 等价于 没有向量可用有限个其他向量的 线性组合 所表示.
1.4 张成 span
对于向量空间中
V
上
1.5 基 basis
若向量空间
V
中向量组
B 中的元素称为基向量。如果基中元素个数有限,就称向量空间为有限维向量空间,将元素的个数称作向量空间的维数。
性质
设
B
是向量空间
V
的基。则
-
V
是
B 的极小生成集,就是说只有 B 能张成 V ,而它的任何真子集都不张成全部的向量空间。 B 是 V 中线性无关向量的极大集合,就是说B 在 V 中是线性无关集合,而且V 中没有其他线性无关集合包含它作为真子集。-
V
中所有的向量都可以按唯一的方式表达为
B 中向量的线性组合。
第三点尤其重要,感性的理解,基就是向量空间中的一个子集,它可以通过唯一的线性组合,来张成向量空间中所有的向量,这样就可以大大的缩小我们向量空间的大小。
1.6 线性相关性引理 Linear Dependent Lemma
如果
(v1,v2,…,vn)
在
V
中是线性相关的,并且
- vj∈span(v1,v2,…,vj−1)
- 如果从
(v1,v2,…,vn)
中去掉第
j
项,则剩余向量组的张成仍然等于
span(v1,v2,…,vn)
证明
设 (v1,v2,…,vn) 在 V 中是线性相关的,并且
v1≠0 , 则有不全为 0 的a1,a2,…,an∈F ,使得
a1v1+a2v2+⋯+amvm=0
a2,a3,…,an 不会全为 0 (因为v1≠0 )。设 j 是{2,…,m} 中使得 aj≠0 的最大者,那么
vj=−a1ajv1−a2ajv2−⋯−aj−1ajvj−1这就有 1 成立.
为了证明 2,设 u∈span(v1,…,vn) , 则存在 c1,c2,…,cn∈F , 使得
u=c1v1+c2v2+⋯+cnvn
在上面的等式中,可以用之前的等式右边来代替 vj . 这样 u 包含于从 (v0,v1,…,vn) 去掉第 j 项的张成,因而 2 成立。
2 性质
设集合
这种线性基的构造方法保证了一个特殊性质,对于每一个
-
ai=0
- 则只有满足
j>i
的
aj
的第
i
个二进制位可能为
1 ;
- 则只有满足
j>i
的
aj
的第
i
个二进制位可能为
-
ai≠0
- 整个
a
数组中只有
ai 的第 i 个二进制位为1 ; - ai 更高的二进制位一定为 0 ;
ai 更低的二进制位可能为 1 ;
- 整个
a
数组中只有
3 流程
线性基是由空一个个加入的,记线性基为
逆序枚举
- 如果
ai≠0 ,则令 t=t⊕ai 。
为保证 a 中只有
ai 的第 i 位为1 ,只有消去 t 的第j 位上的 1 ,才可以继续插入。 如果
ai=0 ,则枚举 j∈[0,i) ,如果 t 的第
j 位为 1 ,则令t=t⊕ak 。为保证 a 中只有
ai 的第 i 位为1 ,只有消去 t 的第j 位上的 1 ,才可以继续插入。枚举
j∈(i,L] ,如果 aj 的第 i 位为1 ,则令 aj=aj⊕t 。为保证 ak,k∈(j,L] 中第 j 位为 0 .
- 令
ai=t ,至此,过程结束。
实现模板
最大异或和
#include<iostream>
#include<cstdio>
typedef long long ll;
const int MAXN=55;
int n;
ll LB[MAXN];
ll LBSeq[MAXN];int scnt;
void insert(ll x)
{
int i,j;
for(i=MAXN-1;i>=0;i--)
{
if((x&(1LL<<i))==0) continue;
if(LB[i]) x^=LB[i];
else
{
for(j=0;j<=i;j++)
if(x&(1LL<<j))
x^=LB[j];
for(j=i+1;j<MAXN;j++)
if(LB[j]&(1LL<<i))
LB[j]^=x;
LB[i]^x;
return;
}
}
}
int main()
{
int i;
scanf("%d",&n);
ll x;
for(i=1;i<=n;i++)
scanf("%d",&x),insert(x);
ll ans=0;
for(i=0;i<MAXN;i++)
if(LB[i]) LBSeq[++scnt]=B[i];
for(i=1;i<=scnt;i++) ans^=LBSeq[i];
printf("lld\n",ans);
return 0;
}
K 小异或和
#include<iostream>
#include<cstdio>
typedef long long ll;
const int MAXN=55;
int n,m;
ll LB[MAXN];
ll LBSeq[MAXN];int scnt;
void insert(ll x)
{
int i,j;
for(i=MAXN-1;i>=0;i--)
{
if((x&(1LL<<i))==0) continue;
if(LB[i]) x^=LB[i];
else
{
for(j=0;j<=i;j++)
if(x&(1LL<<j))
x^=LB[j];
for(j=i+1;j<MAXN;j++)
if(LB[j]&(1LL<<i))
LB[j]^=x;
LB[i]^x;
return;
}
}
}
ll query(ll x)
{
ll res=0;
for(i=1;i<=scnt;i++)
if(x&(1LL<<i))
res^=LBSeq[i];
return res;
}
int main()
{
int i;
scanf("%d",&n);
ll x;
for(i=1;i<=n;i++)
scanf("%d",&x),insert(x);
ll ans=0;
for(i=0;i<MAXN;i++)
if(LB[i]) LBSeq[++scnt]=B[i];
scanf("%d",&m);
while(m--)
{
scanf("%\\d",&x);
if(scnt!=n) --x;
if(x>=(1LL<<scnt)) printf("-1\n");
else printf("lld\n",query(x));
}
return 0;
}