线性基

Posted 租酥雨

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性基相关的知识,希望对你有一定的参考价值。

[模板]线性基

luogu
给定n个整数(数字可能重复),求在这些数中选取任意个,使得他们的异或和最大。
\(1\le n \le 50,0\le S_i \le 2^{50}\)

线性基

线性基其实就是构造出一组序列\(p_0,p_1...p_n\),使得从这些数中任选一个子集的异或和的值域同等与从原序列中任选一个子集的异或和的值域。
同时保证:\(p_i\)在二进制下的最高位是\(2^i\)
这样在求异或和最大的时候就可以按位贪心了。

构造方法:对于一个需要插入线性基的数\(x\),首先找到它在二进制下的最高位\(i\),检查\(p_i\)是否已经生成。若尚未生成则令\(p_i=x\)并结束操作,否则令\(x=x\ \rm xor\ p_i\),并继续插入操作。

放一段线性基的代码:

struct xxj{
    ll p[70];
    void insert(ll x)
        {
            for (int j=63;j>=0;--j)
            {
                if (!(x>>j)) continue;
                if (!p[j]) {p[j]=x;return;}
                x^=p[j];
            }
        }
    ll query(ll x)
        {
            for (int j=63;j>=0;--j)
                x=max(x,x^p[j]);
            return x;
        }
}S;

其中\(\rm query(x)\)是查询异或上\(\rm x\)后的最大值,如果要直接查最大值的话直接\(\rm query(0)\)就好了。

线性基的合并

两个线性基是可以合并的。只要把其中一个暴力插入到另一个里面就行了。

xxj merge(xxj a,xxj b)
{
    for (int j=63;j>=0;--j) if (b.p[j]) a.insert(b.p[j]);
    return a;
}

合并的复杂度是\(O(\log^2n)\)的。

以上是关于线性基的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 4269 再见Xor 线性基

Codeforces 1100F(线性基+贪心)

线性基 刷题记录

P3857 [TJOI2008]彩灯(线性基)

线性基讲解

线性基入门