• 线性基学习笔记


    事实证明在睡过头迟到的下午我可以学会以前学$n$次也不会的东西比如线性基什么的$qwq$

    一个最最重要的性质

    一个数列$left { a_i ight }$,它的子集异或起来能表示的数组成$left { b_i ight }$,令$c=a_i$^$a_j,a_i=c$,子集异或起来还是$left { b_i ight }$.

    证明:对于$left { b_i ight }$中被表示不需要$a_i$的数,显然并不受影响.对于需要$a_i$但不需要$a_j$的数,因为$c$^$a_j=a_i$,所以也能够表示.对于既用到$a_i$又用到$a_j$的数,直接用$c$就好了.

    对以上性质加以推广易知,集合中的任意一个数用这个数异或上其他数(随便几个)来替换,这个集合的自己异或起来表示的数组成的集合不变.再推广,集合中的随便哪些数,用原数异或上.....

    简单总结就是集合里的数异或来异或去再替换替换(随便搞)这个集合的子集异或生成数的集合不会变.

    线性基用来干啥 (简介

    1.判断:子集异或起来能否表示$x$

    2.求异或最大

    3.求异或第$k$大

    线性基是啥/构造线性基

    一堆数字异或来异或去就是线性基 

    $p_i$表示最高位为$1$的是第$i$位的数.对于集合里的每个数,从高位到低位扫,假设现在是数$x$,扫到第$i$位.如果在此之前没有出现以第$i$位为最高位的数,那么就把这个数放进$p_i$,如果以前已经有了呢,那么就$x$异或$p_i$,然后继续往后扫.如果到最后也没找到一个$p_i$用来放$x$呢?这就说明$x$可以被表示.

    就$OK$辣.为什么这样构造呢?首先是正确性,线性基的子集异或值和原集合是一样的,证明就是前面那个重要性质辣.然后是必要性,这也就是我先在前面放用来干啥的原因.因为这样我们保证了最高位为$i$位的数唯一,就可以按位操作了啊,按位判断,按位贪心什么的.

    $Code$

    inline void build()
    {
        go(i,1,n) yes(j,62,0)
            if(a[i]&&(1LL<<j))
            {
                if(!p[j])p[j]=a[i];
                else a[i]^=p[j];
            }
    }

    线性基用来干啥 (具体怎么做

    1.判断:子集异或起来能否表示$x$

    和线性基的构造类似(构造里不是有一种情况就是集合里的数可以被其他数表示嘛).从高位扫到低位,如果$x$在第$i$位上为$1$,$x$^$=p_i$.如果$x$可以变为$0$,那么就可以被表示.

    inline bool sol(ll x)
    {
        yes(i,62,0)if(x&&(1LL<<i))x^=p[i];
        if(!x)return 1;return 0;
    }

    2.求异或最大

    按位贪心.从高位往低位扫,如果异或$p_i$能使答案变得更大,就异或起来.

    正确性:当前扫到第$i$位,前面产生的答案为$ans$.

    若$ans$^$p_i>ans$,说明$ans$在第$i$位上为$0$,异或之后使得$i$位为$1$.那么不过第$i$位往后的数位上的值怎么变,异或后的$ans$一定是更优的(这一位变成$1$后面都是$0$和这一位是$0$后面全是$1$比较一下就知道了.)大概还有一个原因就是过了这村就没这店了,这次不把第$i$位变成$1$,以后就再没可能了.

    若$ans$^$p_i<ans$,说明$ans$在第$i$位上为$1$,异或之后会使得第$i$为变成$0$.所以当然不要异或辣.理解和上一种情况差不多.

    总结一下就是从高位到低位,能变成$1$就变成$1$,不需要考虑更低的位.

    inline ll sol()
    {
        ll ret=0;
        yes(i,62,0)if((ret^p[i])>ret)ret^=p[i];
        return ret;
    }

    3.求异或第$k$大

    解这个问题有点像数位$DP$的试填法.

    首先要$rebuild$线性基,使得$p_i$只有第$i$位为$1$,其他位都是$0$.具体来说从大到小枚举$i$,再从$i-1$到$0$枚举$j$,遇到$p_i$的第$j$位为$1$,就$p_i$^$=p^j$.如果没有以第$j$位为最高位的数呢?对答案没影响.其实准确的描述$rebuild$应该是使得线性基中每一位为$1$的最多只有一个数.

    如果当前位为$i,p_i!=0$,后面有$cnt$位$p_i$不为$0$,那么显然比$p_i$小的数有$2^{cnt}$个.后面就完全是试填法.为了方便起见,我们可以把不为$0$的 $p_i$按照$i$的从小到大顺序加入数组$q$.这样,而且会发现一个非常神奇的做法,就是如果$k$的第$i-1$位为$1$,那么就$ans$^$=q_i$,也就是$k$的从低到高第$i-1$位上是$0$还是$1$决定了选不选$q_i$.($i-1$是因为$q$数组下标c从$1$开始)很好想通叭$qwq$.

    $Attention!!$要特判可以表示出$0$的情况!如果原集合可以表示出$0$,那么第$k$大就是除$0$外的第$k-1$大.怎么判断呢?看原集合的大小和线性基的大小就好了.如果线性基的大小小于原集合,那么就可以表示出$0$,(原集合有数可以被表示出,只要表示出这个数再异或这个数就是$0$)

    inline ll sol(ll k)
    {
        ll ret=0;
        if(k>=(1LL<<ct))return -1;//判断无解情况
        if(ct<n)k--;//判断0能否被表示
        go(i,1,ct)if(k&&(1LL<<(i-1)))ret^=q[i];
        return ret;
    }
    光伴随的阴影
  • 相关阅读:
    css的盒子模型由什么组成?
    div盒子水平、垂直居中
    display:none和visibility:hidden的区别
    创建一个多选框,且和文本关联起来(单击文本就像单击该选框一样)
    Canvas和SVG的不同
    js两个页面之间通过URL传参数
    css a标签去除下划线
    css 设置文本垂直居中
    css 边框圆角的方法
    html 文本框css设置边框圆角
  • 原文地址:https://www.cnblogs.com/forward777/p/11321291.html
Copyright © 2020-2023  润新知