线性基的理解
基(百度百科):在线性代数中,基是描述、刻画向量空间的基本工具。向量空间的基是它一个特殊的子集,基的元素称为向量基。向量空间中任意一个元素,都可以唯一地表示成基向量的线性组合。如果基中元素个数有限,那么称向量空间为有限维向量空间,将元素个数称为向量空间的维数。
定义
若干数的线性基是一组数,其中
的最高位的1在第
位
通过线性基中元素出的数的值域与原来的数
出的数的值域相同
性质
- 线性基是能相互异或出原集合所有相互亦或值的最小集合
- 线性基没有异或和为0的子集(证明参考百度百科的反证法)
插入
就是一个添加过程,对于每一个数,遍历其最高的第位,如果该位上的值为0,那么将该位赋值为插入值;如果不为0,那么两相异或得到一个更小的值,继续向下遍历插入到向量基里面去,这样就把插入值
对向量基的贡献添加进去了。
合并
直接暴力,将其中一个向量基每项插入到另一个之中
查询最大值
初值值为0,我们知道对于异或之后的值,根据贪心我们如果能够得到最高位的1那么最后的值肯定比较大,我们又知道线性基的线性组合能够表示所有的异或值。那么我们在得到第一个最高位数的前提下去考虑其他位的数在它身上的叠加效果,于是在这个过程中从高到底遍历,如果异或得到的数更大,就更新答案,(有点类似二分的过程)。
查询最小值
不用考虑,最低位的非0值就是最小值,因为没有更小位上的1能让该值变得更小了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=65;
typedef long long ll;
ll b[maxn];
///单个元素插入线性基以及构建线性基
void add(ll x){
for(int i=63;i>=0;--i){
if(x&(1ll<<i)){
if(!b[i]){
b[i]=x;
break;
}else x^=b[i];
}
}
return ;
}
///将a数组插入b之中,合并
void two_merge(ll a[]){
for(int i=63;i>0;++i)
add(a[i]);
return ;
}
///查询最大值
ll query_max(){
ll ans=0;
for(int i=63;i>=0;--i)
if((b[i]^ans)>ans)
ans^=b[i];
return ans;
}
ll query_min(){
for(int i=0;i<=63;++i)
if(!b[i])return b[i];
}
///得到每位最小值,就是基础分量
///返回紧凑后的长度
int rebuild(){
for(int i=62;i>=0;--i){
if(b[i]){
for(int j=i+1;j<=63;++j){
///判断该位上面是否有值
if(b[j]&(1ll<<i)) b[j]^=b[i];
}
}
}
int cur=0;
for(int i=0;i<=63;++i)
if(b[i])b[cur++]=b[i];
return cur;
}
/*
while(q--){
ll x;
cin >> x;
ll ans=0;
if(n!=cur)--x;//取到了0
if(x>=(1ll<<cur)){printf("-1\n");continue;}
for(int i=63;i>=0;--i){
if(x&(1ll<<i)){
ans^=b[i];
}
}
cout << ans << endl;
}
*/
int main()
{
return 0;
}