线性积基于线性代数中的无关向量组
回顾线性代数中的无关向量组的无关性,若两个向量线性相关,肯定可以相互表示,
ax1+bx2+cx3=0有不全为0的数表示,则说明向量组x1 x2 x3是线性相关的
若一个矩阵可逆,还有他的秩不为0,构成这个矩阵的向量组线性无关
1.线性基的异或集合中不存在0。
2.线性基的异或集合中每个元素的异或方案唯一
3.线性基二进制最高位互不相同。
4.线性基中元素互相异或,异或集合不变。
5.可以把n个数变成只有最大的数的二进制位数那么多个数
6.n个数的线性基最多只有个n个数中最大的那个数的二进制的位数个多的数
7.也就是有log2n个数字
8. 每一个数字出现的次数是相同的都是2^(n-cnt)个,cnt是线性基中元素得个数
(注意: 就是0能不能被异或出来。如果线性基的大小和原数组一样,0是不能被异或出来的,否则可以,在求的时候要注意这一个性质,hdu3949在求k大值的时候就用到了)
一、构造线性基
void build(ll p)
{
for(int x=62;x>=0;--x)
{
if(p&(1ll<<x))// 扫描到最高位的1(位置在位置x处)
//if((p>>x)==1)或者是这种形式,都可以找出p最高位为1的位置x
{
if(a[x]==0)//如果ax不存在
{
a[x]=p;//那么a[x]就等于p
break;//并且结束
}
p^=a[x];//否则p就等于 p^a[x];
}
}//最终p要么变为线性基中的一个数a[x],要么变成了0
}//通过传递一组数pi,那么这组数的线性基就构造完成了。
//而且这样构造出来的线性基(一组数)a1 a2 a3..ax ai的最高为的1在第i位置
二、求出最大值
// 1、用线性基求这组数xor出的最大值:从高往低扫ax,若异或上ax使答案变大,则异或。
ll query_max()
{
ll ret=0;
for(int i=63;i>=0;--i)
{
if(ret^a[i]>ret)
{
ret^=a[i];
}
}
return ret;
}
三、求出最小值
//异或的最小值、最小值即为最低位上的线性基。
ll query_min()
{
for(int i=0;i<=63;++i)
if(a[i])
return a[i];
return 0;
}
四、俩线性基合并
//合并两个线性基、将一个线性基暴力插入另一个线性基中就可以得到两个原数组中合并之后的线性基了
void merge(int a1[],int a2[])
{
int ret[maxn];
ret=a1;
for(int i=0;i<=63;++i)
{
if(a2[i])
ret.insert(a2[i]);
}
return ret;
}
五、求线性基的k小值
/* 求异或的K小值
我们要将线性基改造成每一位相互独立。
具体操作就是如果j<i,ai的第j位是1,就将ai异或上aj
对于二进制的某一位j。只有aj的这一位是1,其他都是0。
所以查询的时候将k二进制拆分,对于1的位,就异或上对应的线性基。
最终得出的答案就是k小值。
*/
void rebuild()
{
for(int i=62;i>=0;--i)
{
for(int j=i-1;j>=0;--j)
if(a[i]&(ll(1<<j)))
a[i]^=a[j];
}
for(int i=0;i<=60;++i)
if(a[i])
p[cnt++]=a[i];
}
ll quety_Kth(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;
}
六、查询某一个值是否是由线性基得到
//查询某一个值是否是由线性基得异或和得到得
void query(ll x)
{
for(int i=62;i>=0;--i)
{
if((x>>i&1)&&a[i])
x^=a[i];
}
return x==0;//成立就是可以得到
}