【算法笔记】对两种线性基的理解

博客介绍了线性基的两种形式。原始线性基通过对给定数组元素逐位检查,将元素填入线性基数组,不为0的线性基元素可组合出所有异或值。而力求满足对角矩阵的线性基,在填入元素时会进行额外消元处理,可用于求异或第k小的数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

五个数:a[5]={6,7,2,3,4},a[i]=(b_n....b_2b_1b_0)_2,从高位到低位检查a[i]的每一位是否位1,p[]存线性基

原始的线性基:


对于a[i],如果a[i]的j位为1

  • p[j]=0,p[j]=a[i]
  • p[j]!=0,表明已经填入数了,a[i]^=p[j],继续遍历新的a[i]的下面的位,判断是否是1

所以这五个数对应的行阶梯矩阵为:

\begin{bmatrix} 0&0&0&0\\ 0 &1&1&0\\ 0&0&1&0\\ 0&0&0&1 \end{bmatrix}

如果p[j]=0,那么这个a[i]就先入为主的填到p[j]的位置,且不会再更新这个p[j]

如果p[j]已经有数了,那么消去a[i] j位的1(a[i]^=p[j]),再往后找可以填入的p[j],每次无法填入的时候都要消去a[i] j位的1,最终如果a[i]=0, 说明a[i]和a[i]前面出现的数异或会得到0。BZOJ2460就是用这种思路求解的。

这些不为0的p[i]又可以组合成 给出的n个数能得到的所有异或值

To sum up:

p[j]表示的是在顺序遍历a[]时,最先出现的 j位为1的异或值(可能是由1个数得到的,也可能是多个数异或得到的,但未必就是j位为1的最大的异或值)

a[i]无法填入(最终a[i]=0),说明a[i]和它前面出现的数异或会得到0。

这些不为0的p[i]又可以组合成 给出的n个数能得到的所有的异或值BZOJ2115就利用了这个性质

模版:

void getXian()
{
    for(int i=0;i<n;i++)
    {
        for(int j=max_base;j>=0;j--)
        {
            if(a[i]>>j&1)
            {
                if(p[j])
                    a[i]^=p[j];
                else
                {
                    p[j]=a[i];
                    break;
                }
            }
        }
    }
}

力求满足对角矩阵的线性基:


最开始学线性基的时候,大佬们讲的都是这种线性基:https://blog.sengxian.com/algorithms/linear-basis

它和原始的线性基的不同之处在于:在把a[i]填入p[j]时,要用p[j]下面的行消去p[j]的j位之后的1,用p[j]消去p[j]上面行中j位为1的p[k] (因为不为0的p[j]的j位一定是1)。这样处理完之后的行阶梯矩阵就和对角矩阵很接近了,具体讲解在这里

所以这五个数对应的行阶梯矩阵为:

\begin{bmatrix} 0&0&0&0\\ 0 &1&0&0\\ 0&0&1&0\\ 0&0&0&1 \end{bmatrix}

To sum up:p[j]表示由n个数得到的j位为1的最小的异或值,利用这个性质就可以求n个数异或得到的第k小的数

注意:如果得到的线性基的p[j]不为0的数目num和给出的数字数目n相同的话,那么这n个数无法通过异或得到0

模版:

void getXian()
{
    for(int i=0;i<n;i++)
    {
        for(int j=max_base;j>=0;j--)
        {
            if(a[i]>>j&1)
            {
                if(p[j])
                    a[i]^=p[j];
                else
                {
                    p[j]=a[i];
                    for(int k=j-1;k>=0;k--)
                        if(p[j]>>k&1)
                            p[j]^=p[k];
                    for(int k=j+1;k<max_base;k++)
                        if(p[k]>>j&1)
                            p[k]^=p[j];
                    break;
                }
            }
        }
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值