线性基

Linear Basis线性基
话说HAOI 2017八纵八横是个比较裸的线性基,但是那会还没学。。。

目录

基本概念

  • 异或和
    定义一个无符号整数集合S(注意,我们接下来讨论的集合均指由无符号整数为元素构成的集合),则S的异或和就是S中所有元素互相异或的结果.
    通俗的用伪C++代码表示就是:
unsigned int S[MAXN]={...};
unsigned int xor_sum=0;
for(int i=1;i<MAXN;++i)
    xor_sum^=S[i];
  • 张成
    定义子集 TiS ,则所有 Ti 的异或和组成的集合B就是S的张成,记做B=span(S).
    通俗的说,就是S的张成在S中任取一些元素求异或和的所有可能结果的异或和;
    也可以理解为用S中的元素通过互相异或可以表示的数的集合.

  • 线性相关
    如果存在一个元素x∈S,且从S中去除出x后S的张成span(S’)包含x,则说S是线性相关的;
    简单的说,就是x可由S中的其它某些元素互相异或得来;

    显然,当S去除出x后,S的张成不变.

  • 线性基
    首先,线性基是一个集合,并且更严格的说,一个线性基应该是某个集合的线性基;
    我们说一个集合B是集合S的线性基,当且仅当B满足以下条件:

    1. B⊆span(S);
    2. B是线性无关的(即不满足线性相关的条件).
      也就是说,B中所有元素均可由S中的某些元素互相异或得来;
      其实,进一步推理可知:S中的元素也都可以由B中某些元素互相异或得来(提示:x^x=0),并且要想满足这个条件,B中元素已经是缺一不可了;

    所以,一个集合的线性基是可以表示这个集合的最小集合.

算法步骤

可以说,线性基的构造用到了贪心的思想,具体如下:

  • 插入元素x时,从高位到低位扫;
  • 如果线性基集合B[i]!=0,则x^=B[i],消去x的第i位;
  • 如果B[i]==0,则B[i]=x,但需注意,要再从高到低把B[j]^=B[i](j>i),消去B[j]的第i位;同时B[i]^=B[j](j

代码

inline void ist(long long x){
    for(int i=MAXN-1;i>=0;--i){
        if(((x>>i)&1)==0) continue;
        if(LB[i]) x^=LB[i];
        else{
            for(int j=0;j<i;++j){
                if((x>>j)&1) x^=LB[j];
            }
            for(int j=i+1;j<MAXN;++j){
                if((LB[j]>>i)&1) LB[j]^=x;
            }
            LB[i]^=x;
            return;
        }
    }
}

应用

  • 子集异或和最大
    1. 显然先构造线性基;
    2. 然后贪心,从高到低,如果ans的第i位为0,则异或上LB[i];
long long ans=0;
    for(int i=MAXN-1;i>=0;--i){
        if(((ans>>i)&1)==0)
            ans^=LB[i];
    }
  • 子集异或和第k小
    1. 还是先构造一个线性基;
    2. 但,我们要考虑,对于ans,在高位异或出一个1更能使ans变大;而低位上异或出一个1必然会使ans变大;
    3. 所以,我们考虑将线性基集合的非0元素从小到大加入一个vector中,然后由于每个线性基元素对ans大小的影响与k中每位相同,我们只需判断k的第i位为1否,然后异或vector[i]就好;
    4. 注意,线性基子集的非0异或和情况只有 2vector.size() 个,所以我们还要判断是否能异或出第k小.
inline void prepare(){
    for(int i=0;i<MAXN;++i){
        if(LB[i]) V.push_back(LB[i]);
    }
}

inline long long query(const long long &k){
    if(V.size()!=n) --k;
    if(k>=(1LL<<V.size())) return -1;
    long long s=0;
    for(int i=0;i<V.size();++i){
        if((k>>i)&1)
            s^=V[i];
    }
    return s;
}

非常感谢menci大大的博客,还有他题库上的模板题,%%%.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值