初见 | 数据结构 | 线性基

主要参考了 Menci 的线性基学习笔记

「前置知识」

一些线性基能用到的。

下文中若未特殊说明,集合均为「无符号整数集」。

「异或和」

对于集合 \(S\),将其中所有元素异或起来的结果。

「张成」

对于集合 \(S\) 的所有子集的异或和组成的集合成为 \(S\)张成,记作 \(span(S).\)

换句话说就是在 \(S\) 中选出任意多个数,其异或和的所有可能的结果组成的集合。

「线性相关」

对于一个集合 \(S\),如果存在一个元素 \(i\),使得,\(S\) 在去除这个元素后得到的集合 \(S'\) 的张成 \(span(S')\) 中包含 \(i\),即,\(i\in span(S')\),则称集合 \(S\) 线性相关。

换句话说就是 \(S\) 中存在一个元素 \(i\) 可以被 \(S\) 中的其他的若干个元素异或得到。

如果不存在这样的 \(i\),就说 \(S\) 线性无关。

一个显然的结论是对于一个线性相关的集合 \(S\),去掉符合条件的 \(i\) 之后,\(span(S)\) 不变。

「线性基」

称集合 \(LB\) 为集合 \(S\) 的线性基,当且仅当:

  1. \(S\in span(LB).\)

  2. \(LB\) 线性无关。

\(LB\) 中的元素个数,称为线性基的长度。

线性基有以下的性质:

  1. \(LB\) 是极小的满足线性基性质的集合,它的任何真子集都不可能是线性基;

  2. \(S\) 中的任意元素都可以唯一表示为 \(LB\) 中若干个元素异或起来的结果;

  3. 线性基里任意一个子集的异或和都不为\(0.\)

「模板」

下面是模板。

「构造」

I void Insert(int x)
{
    for(int i(62);i>=0;--i)
    {
        if(x&(1<<i))
        {
            if(!p[i])
            {
                p[i]=x;
                
                Heriko;
            }
            else
                x^=p[i];
        }
    }
}

「查询元素是否存在」

因为“\(S\) 中的任意元素都可以唯一表示为 \(LB\) 中若干个元素异或起来的结果”,所以如果一个数在不断异或的过程中,能变成 \(0\),那就存在于集合中。

I bool Query(int x)
{
    for(int i(62);i>=0;--i)
        if(x&(1<<i))
            x^=p[i];

    Heriko !x;
}

「查询异或最大值」

贪心即可。

I int XorMax(int x)
{
    int res(0);

    for(int i(62);i>=0;--i)
        if((res^p[i])>res)
            res^=p[i];

    Heriko res;
}

「查询异或最小值」

贪心即可,但是要特判 \(0\),即存在 \(0\) 的时候最小值为 \(0.\)

I int XorMin(int x)
{
    if(HaveZero)
        Heriko Deltana;

    for(int i(62);i>=0;--i)
        if(p[i])
            Heriko p[i];
}

暂且就先这些,还有一个查询第 \(k\) 大异或值的操作,因为我还没用过所以就先不写。

posted @ 2021-12-10 10:06  HerikoDeltana  阅读(60)  评论(1编辑  收藏  举报