线性基
概念
线性基是针对某个序列生成的一个集合,它具有以下两条性质:
线性基中任意选择一些数的异或值所构成的集合,等于原序列中任意选择一些数的异或值所构成的集合。
线性基是满足上述条件的最小集合。
原序列中任何数,都可以由线性基中一些数异或起来得到(由性质1直接得出)
线性基中不存在一组数,使得它们的异或值为0,如果存在x xor y xor z=0则等价于x xor y =z使得异或集合变,违背了性质2)
线性基中不存在两组取值集合,使得它们的异或和相等(不然你把这两个集合异或在一起就会得到异或和为0的集合)
线性基中的数最高位数字1不重复
线性基个数小于等于原数个数
cpp
struct LinearBasis{
vector<int> d;
int fail,mxb;
static constexpr int SIZE=60;
vector<int> nums;
LinearBasis(){
init();
}
void init(){
d.assign(SIZE,0);
fail=mxb=0;
}
bool insert(int x){
for(int i=SIZE-1;i>=0;i--){
if(!(x>>i&1))continue;
mxb=max(mxb,i);
if(d[i])x^=d[i];
else{
d[i]=x;
return true;
}
}
fail++;
return false;
}
int query_max(int res=0){
for(int i=SIZE-1;i>=0;i--){
res=max(res,res^d[i]);
}
return res;
}
int query_min(int res=0){
if(!res)return fail?0:*min_element(d.begin(),d.begin()+mxb+1);
for(int i=SIZE-1;i>=0;i--){
res=min(res,res^d[i]);
}
return res;
}
void rebuild(){
nums.clear();
for(int i=0;i<SIZE;i++){
for(int j=0;j<i;j++){
if(d[i]>>j&1)d[i]^=d[j];
}
if(d[i])nums.push_back(d[i]);
}
}
int kth(int k,int n){
if(nums.size()<n){
if(k==1)return 0;
k--;
}
if(k>=(1ll<<nums.size()))return -1;
int res=0;
for(int i=SIZE-1;i>=0;i--){
if(k>>i&1)res^=nums[i];
}
return res;
}
int find_rank(int x){
int rk=0,tp=1,y=x;
for(int i=0;i<SIZE;i++){
if(!(y>>i&1))continue;
if(d[i])y^=d[i];
else return -1;
}
for(int i=0;i<SIZE;i++){
if(d[i]){
if(x>>i&1)rk+=tp;
tp<<=1;
}
}
return rk;
}
LinearBasis operator|(const LinearBasis &rhs)const{
LinearBasis res=*this;
for(int i=0;i<SIZE;i++){
if(rhs.d[i])res.insert(rhs.d[i]);
}
return res;
}
LinearBasis operator&(const LinearBasis &rhs)const{
LinearBasis res;
auto d=*this,all=*this;
for(int i=0;i<SIZE;i++){
if(!rhs.d[i])continue;
int k=0,j;
int v=rhs.d[i];
for(j=i;j>=0;j--){
if(v>>j&1){
if(all.d[j])v^=all.d[j],k^=d.d[j];
else break;
}
}
if(!v)res.d[i]=k;
else all.d[j]=v,d.d[j]=k;
}
return res;
}
};贪心构造
cpp
int d[60];
void insert(int x){
for(int i=55;i>=0;i--){
if(!(x>>i&1))continue;
if(d[i])x^=d[i];
else{
d[i]=x;
break;
}
}
}
//查询异或最大值
int query(){
int res=0;
for(int i=55;i>=0;i--){
if(res>>i&1)continue;
res^=d[i];
}
return res;
}
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
insert(x);
}
cout<<query()<<"\n";
}高斯消元法构造
cpp
int d[70];
void gauss(int n){
int k=1;
for(int i=62;i>=0;i--){
for(int j=k;j<=n;j++){
if(d[j]>>i&1){
swap(d[j],d[k]);
break;
}
}
if(!(d[k]>>i&1))continue;
for(int j=1;j<=n;j++){
if(j!=k&&(d[j]>>i&1))d[j]^=d[k];
}
if(k==n)break;
k++;
}
}
void insert(int x){
for(int i=55;i>=0;i--){
if(!(x>>i&1))continue;
if(d[i])x^=d[i];
else{
d[i]=x;
break;
}
}
}
int query(){
int res=0;
for(int i=55;i>=0;i--){
res^=d[i];
}
return res;
}
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>d[i];
gauss(n);
cout<<query()<<"\n";
}求min异或值
- 当某次数插入失败时,异或值为0
- 否则为min d[i]
求第k小异或和
- 重构线性基,使得每一位在线性基中只有当前位为1
- 求第k小直接对k二进制拆分算异或即可
- 注意:如果
d[i]不为0的个数小于n,说明有插入失败,存在异或为0,询问需要减一
cpp
int d[70];
void insert(int x){
for(int i=55;i>=0;i--){
if(!(x>>i&1))continue;
if(d[i])x^=d[i];
else{
d[i]=x;
break;
}
}
}
vector<int> nums;
void rebuild(){
for(int i=0;i<=55;i++){
for(int j=i-1;j>=0;j--){
if(d[i]&(1ll<<j))d[i]^=d[j];
}
if(d[i])nums.push_back(d[i]);
}
}
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
int x;
cin>>x;
insert(x);
}
rebuild();
int m;
cin>>m;
while(m--){
int x;
cin>>x;
if(nums.size()<n)x--;
if(x>=(1ll<<nums.size()))cout<<"-1\n";
else{
int ans=0;
for(int i=55;i>=0;i--){
if(x>>i&1)ans^=nums[i];
}
cout<<ans<<"\n";
}
}
}求异或路径(最大值最小值)
- 建立dfs树,把所有的环异或值加进线性基
- 查询与异或的最大值(最小值)
实数线性基
cpp
const double eps=1e-6;
template <typename T>
struct Vector{
vector<T> a;
Vector(int n):a(n){}
T& operator[](int i){
return a[i];
}
const T& operator[](int i)const{
return a[i];
}
Vector operator-(const Vector &b){
Vector res(a.size());
for(int i=0;i<a.size();i++)res[i]=a[i]-b[i];
return res;
}
Vector operator*(const T &x){
Vector res(a.size());
for(int i=0;i<a.size();i++)res[i]=a[i]*x;
return res;
}
Vector operator/(const T &x){
Vector res(a.size());
for(int i=0;i<a.size();i++)res[i]=a[i]/x;
return res;
}
};
template <typename T>
struct LinearBasis{
vector<Vector<T>> d;
int n;
LinearBasis(){}
LinearBasis(int n){
init(n);
}
void init(int n){
d.assign(n,Vector<T>(n));
this->n=n;
}
bool insert(Vector<T> x){
for(int i=n-1;i>=0;i--){
if(fabs(x[i])<eps)continue;
if(fabs(d[i][i])<eps){
d[i]=x;
return true;
}
x=x-d[i]*(x[i]/d[i][i]);
}
return false;
}
};