zoukankan      html  css  js  c++  java
  • 浅谈线性基

    几个概念或引理

    概念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
    ",s.qmax());
        return 0;
    }
  • 相关阅读:
    Spring配置文件的命名空间URI
    Hibernate @Embeddable注释
    HIbernate实体类注解配置
    Hibernate关系映射之many-to-many
    Hibernate中cascade属性的区别
    Hibernate注解配置与XML配置区别
    JPA关系映射之one-to-one
    Mysql修改id自增值
    JPA关系映射之one-to-many和many-to-one
    swift
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/9447936.html
Copyright © 2011-2022 走看看