思路
线性基模板题
线性基
一个向量空间中既是线性无关,同时又能张成该向量空间的向量组V称为向量空间的基。
acm中线性基通常用来计算子集异或问题,如子集最大,最小,第k大异或和,线性基有一个非常重要的性质:
对于任意一个存在于线性基的二进制位,至多只有一个数bj满足第i位为1
也就是说如果我们要选第k大的异或值,我们只要选择k各个二进制位换算成的数在线性基中是第几个数,然后异或一下就是第k大的(因为两两行之间不会出现抵消使得结果变小)。
线性基求法
线性基的求法与线性代数正交基的构造方法——格拉姆-施密特方法非常像,大家可以类比地去学习。
假定我们读入n个数,存放在a[n],再令b[MAXP]为我们的线性基数列,MAXP为读入数二进制位的最大位数。若我们构造到a[n],我们从高位到低位进行计算。若计算到第j位,我们发现a[i]的二进制位有这个1,那我们看b[j]的基是否已经存在,如果存在,那么我们吧b[j]的影响从a[i]中减掉,表现为b[j]^=a[i],如果不存在,那么我们b[j]=a[i],同时先将比b[j]小的基对b[j]的影响消除,表现为b[j]^=b[k];。对比b[j]大的基,我们要消除b[j]对他们的影响,表现为算法中的b[k]^=b[j]。我们重复计算后就能算出a的线性基。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16void build(ll *a,ll n){
ms(b,0);
for(int i=0;i<n;i++){
for(int j=MAXP;j>=0;j--){
if((a[i]>>j)&1){
if(b[j])a[i]^=b[j];//eliminate the influence of b[j] in a[i];
else{
b[j]=a[i];
for(int k=j-1;k>=0;k--)if(b[k]&&((b[j]>>k)&1))b[j]^=b[k];
for(int k=j+1;k<=MAXP;k++)if(b[k]>>j&1)b[k]^=b[j];
break;
}
}
}
}
}
思路
本题是线性基第k小的模板题。思路上问讲过,不过要注意当出现无法插入的值的时候,说明有向量线性相关,所以我们要考虑异或值可以生成0(线性基没有考虑生成0)。
参考
代码
1 |
|