• 线性基小结


    线性基是用来处理异或和的一大利器,对于一个数集(S),它的线性基是一个最小的集合(S_1),使得(S)内元素异或得到的值的值域与(S_1)内元素的值的异或得到的值的值域相同

    很明显一个序列的线性基具有如下的性质:集合内元素相互异或得到的值不可能为0

    证明:反证法,假设存在(a_1,a_2,cdots,a_p)使得(a1 xor a2 xor cdots xor a_p=0)

    ​ 由异或的性质就可以得到(a_1=a_2 xor cdots xor a_p)

    ​ 对于某一个数(x=a_1 xor y),如果(y)能被该线性基用异或表示,那么将(a_1)(y)异或在一起来表示(x)的话,无论怎么样都不会用到(a_1)

    ​ 即存在一个更小的线性基([a_2,a_3,cdots,a_n])(a_1)是无用的,这与线性基的定义相矛盾,原命题得证

    由上面的性质你可以得到如下推论:如果某个数(x)可以被这个线性基表示出来,那么这个表达方式唯一(证明也可以使用反证法)

    构造

    对于一个给定的序列,如何构造它的线性基呢?

    我们记原来的序列为(a_1,a_2,cdots,a_n),它的线性基为(p_1,p_2,cdots,p_m)(其中(m)(a_i)中的数在二进制表示下的最大位数)

    同时我们规定,(p_i)的二进制表示中最高位是第(i)位且这一位为1

    也就是说,对于一个(p_i)只会有

    ​ 1)若(p_i=0),则只有可能在满足(j>i)(p_j)的二进制表示的第(i)上出现1

    ​ 2)若(p_i ot=0),那么(p_i)中比第(i)位更高的位上一定是0,但比第(i)为更低的位上有可能出现1;并且对于所有的(j>i)(p_j)中的第(i)位上一定是0

    流程的话我们考虑每一次(insert)一个数

    假设当前(insert)的数是(x),我们从高位向低位枚举,如果当前(x)的最高位对应的线性基(p_i)为0,那么就令(p_i=x)并且结束;否则就令(x=x xor p_i)并且继续枚举

    这样做显然不会破坏之前出现的值域,并且当我们考虑由这个数与其他数组成的新的异或值,由上面的操作我们知道(x)是可以被线性基中的某些数得到的,所以我也可以用这些数与其他数组合来得到新的异或值(即由操作过程我们是有(x=p_{i_1} xor p_{i_2} xor cdots xor p_{i_k})的)

    合并

    合并操作类似于插入操作,将线性基(A)中的所有元素依次插入线性基(B)中即可

    查询

    一般的查询就是询问一个数(x)能否被当前的线性基表示出来

    这个问题与插入十分相似,对(x)的最高位逐步考虑即可

    从线性基的最高位开始往下遍历,如果当前位(L)(x)的最高非0二进制位,则令(x=x xor p_L),一直到遍历完成,如果此时(x)为0则该数可以被表示出来,反之则不可(其实本质就是贪心,考虑必须要将当前的最高位消去即可证明)

    应用

    比较经典的就是查询某个数集内的最大(小)异或和

    建出线性基之后考虑贪心,从高到低遍历线性基,如果当前取这一位对答案有贡献就取(可以从当前线性基的最高位对答案影响开始考虑,如果取当前的线性基的话,有构造可知对后续的线性基是否选取也会有影响)

    最小异或和的话直接取最小的非(0)(p_i)即可(妈耶还是贪心

    例题

    Luogu3812 模板线性基

    codeforces1101G. (Zero XOR Subset)-less

  • 相关阅读:
    c# 遮罩
    判断当前task中的运行的activity是否为当前应用
    Chrome+SwitchySharp+myentunnel+SSH
    vps
    系统制作
    vs2010 mfc
    android ndk
    乐 Phone刷机教程(全过程)
    mysql 保留字 冲突
    mysql 存储过程
  • 原文地址:https://www.cnblogs.com/encodetalker/p/10299247.html
Copyright © 2020-2023  润新知