浅谈线性基

几个概念或引理

概念1:数集的异或和:定义一个无符号整数集合S(注意,我们接下来讨论的集合均指由无符号整数为元素构成的集合),则S的异或和就是S中所有元素互相异或的结果.

概念2:张成:子集Ti ⊆  S且子集Ti异或和组成的集合K就是数集S的张成,记做K=span(S)就可以理解为S中取任意多个元素异或运算获得的值组成的集合就是S的张成K。

概念3:线性相关和线性无关:

线性相关: 设元素x∈S,数集去除元素x后的数集为S’,且满足x∈span(S’)即 span(S)=span(S’),就可以理解为去除x元素后集合S对于异或运算获得值组成的集合没有变化,也可以这么说——x可由S中的其它某些元素互相异或得来。这样的元素x就称x与S线性相关。

线性无关:不满足线性相关的元素x,就称x与S线性无关。

概念4:线性基:设集合B是集合S的线性基,当且仅当满足如下条件

  1. B是span(S)的子集,就是说B必须是S张成中任意数组成的集合
  2. B中的任意元素x与S是线性无关的,也就是说,B中所有元素均可由S中的某些元素互相异或得来

引理1:基于概念4,通过推理可知线性基是对于xor运算表示S集合的最小表示方法,是缺一不可的,所以,一个集合的线性基是可以表示集合S xor 运算组成值得最小的集合。

引理2:异或运算的自反性:即a xor b=c ↔ a=b xor c; b=a xor c;

       异或运算的交换律:即a xor b=c ↔b xor a=c;

       异或运算的结合律:即a xor b xor c ↔ a xor  (b xor c)

其他1:构造线性基时为了处理方便(减小时间复杂度),在线性基集合中满足单调性(增)

 

贪心算法构造线性基

设线性基集合B是S集合的线性基;

每次插入元素x,从B集合高位到低位扫;(从大到小,使元素越异或越小)

设目前线性基到元素编号为i,B[i]有两种情况==0或非0,分别考虑:

B[i]!=0:x^=B[i](证明一下:设原来的数为x,异或B[i]后的值为x’,有x’=x ^ B[i],由引理2可知x= x’ ^ B[i],也就是说元素x可以从x’和B[i]两个元素构造而来,也可以称作对元素x进行xor运算的一种拆分)

B[i]==0:先把B[i]=x;对高位进行遍历B[j]^=B[i] {j>i}(目的是把高位B[j]消到最小),

同时B[i]^=B[j] {0≤j<i} (目的是把B[i]消到最小)

操作后显然保证线性基B[i]是单调(增)。

这里给出线性基运算的几个模板:

struct base_link{
    vector<ll> v;
    int num; bool rel;
    base_link(){ //初始化 
        memset(B,0,sizeof(B));rel=false;
        v.clear(); num=0;
    }
    void insert(ll x){ //插入 
        for (int i=62;i>=0;i--) {
         if (!(x >> i & 1)) continue;
         if (B[i]) x^=B[i];
         else {
           for (int j=0;j<i;j++)  if (x>>j & 1) x^=B[j];
            for (int j=i+1;j<=62;j++) if (B[j]>>i & 1) B[j]^=x; 
            B[i]=x; num++;
           return; 
          }
        }
        rel=true;
    }
    void basis() { //变成vector 
        for (int i = 0; i <= 62; ++i)  if (B[i]) v.push_back(B[i]);
    }
    bool check(ll x) { //查找通过xor运算产生x是否可能 
        for (int i=62;i>=0;i--) {
         if (!((x>>i)&1ll)) continue;
         if (B[i]) x^=B[i]; else return false;
         if (x==0ll) break;
        }
        return true;
    }
    ll size() { //求xor产生元素种类 
        return ((1ll<<num)-1ll);
   }
    ll qmax() { //求子集xor最大 
        ll ans=0ll;
        for (int i=0;i<v.size();i++) 
          if ((ans^v[i])>ans) ans^=v[i];
        return ans; 
    }
    ll qmin() { //求子集xor最小 
        if (size()==0) return -1;
        return v[0];
    }
    ll qminkth(ll x) { //求子集xork小 
        ll ret = 0;
        if (rel) x--;
        if (x>size()) return -1;
        for (int i = 0; i < v.size(); ++i) if (x >> i & 1) ret ^= v[i];
        return ret;
    }   
    ll qmaxkth(ll x) { //求子集xork大 
        return qminkth(size()-x+1);
    } 
}s;

可编译代码:

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=100005;
ll B[MAXN];
int n;
struct base_link{
    vector<ll> v;
    int num; bool rel;
    base_link(){ //初始化 
        memset(B,0,sizeof(B));rel=false;
        v.clear(); num=0;
    }
    void insert(ll x){ //插入 
        for (int i=62;i>=0;i--) {
         if (!(x >> i & 1)) continue;
         if (B[i]) x^=B[i];
         else {
           for (int j=0;j<i;j++)  if (x>>j & 1) x^=B[j];
            for (int j=i+1;j<=62;j++) if (B[j]>>i & 1) B[j]^=x; 
            B[i]=x; num++;
           return; 
          }
        }
        rel=true;
    }
    void basis() { //变成vector 
        for (int i = 0; i <= 62; ++i)  if (B[i]) v.push_back(B[i]);
    }
    bool check(ll x) { //查找通过xor运算产生x是否可能 
        for (int i=62;i>=0;i--) {
         if (!((x>>i)&1ll)) continue;
         if (B[i]) x^=B[i]; else return false;
         if (x==0ll) break;
        }
        return true;
    }
    ll size() { //求xor产生元素种类 
        return ((1ll<<num)-1ll);
   }
    ll qmax() { //求子集xor最大 
        ll ans=0ll;
        for (int i=0;i<v.size();i++) 
          if ((ans^v[i])>ans) ans^=v[i];
        return ans; 
    }
    ll qmin() { //求子集xor最小 
        if (size()==0) return -1;
        return v[0];
    }
    ll qminkth(ll x) { //求子集xork小 
        ll ret = 0;
        if (rel) x--;
        if (x>size()) return -1;
        for (int i = 0; i < v.size(); ++i) if (x >> i & 1) ret ^= v[i];
        return ret;
    }   
    ll qmaxkth(ll x) { //求子集xork大 
        return qminkth(size()-x+1);
    } 
}s;
int main()
{
   long long t; scanf("%d",&n);
    memset(B,0ll,sizeof(B));
    for (int i=1;i<=n;i++) {
      scanf("%lld",&t);
      s.insert(t);  
    }
    s.basis();
    printf("%lld\n",s.qmax());
    return 0;
}

 

posted @ 2018-08-09 11:39  ljc20020730  阅读(170)  评论(0编辑  收藏  举报