线性基详解+例题

线性基

线性基是一个能够在每次时间复杂度\(O(\log_2d)\),d是数字的位数内处理异或最大最小的数据结构。

问题:请你维护一个数据结构,支持插入一个数,求这些数任意异或得到的结果是否可能为某一个数、最大值、最小值、第k小值。

做法:开一个数组a[MAXN],MAXN是数字最高位数。

a[i]表示当前线性基内任意异或出来的数字中,最高位为i的任意一个数字。

#define MAXN 60
long long a[64];

插入x|判断x是否可以由线性基得到

用下面的数举例
x1:10101 x2:10001 x3:11000 x4:11011 x5:10111 x6:01101

高位到低位 枚举所有位数,如果x的第i位为0则不管,如果x的第i位为1:

1.如果a[i]不存在,更新线性基 a[i]=x,并退出。

2.如果a[i]存在,令x^=a[i]。

如果最后x变成了0,那么说明x可以由线性基异或得到。

void Insert(long long x)
{
    for(int i = MAXN; i >= 0; i--)
    {
        if(x & (1LL << i))
        {
            if(!a[i]){a[i] = x;return;}
            x ^= a[i];
        }
    }
}

查询最大值

从高位到低位扫描线性基。如果异或之后答案变大,就把这一位异或到答案。

long long getmax()
{
    long long ans = 0;
    for(int i = MAXN; i >= 0; i--)
    {
        if((ans ^ a[i]) > ans)
            ans ^= a[i];
    }
    return ans;
}

查询最小值

要先判断一下是否可能是0。

不可能是0则像下面这样从低位到高位扫描线性基。最低位上的线性基即为答案。

long long getmin()
{
    for(int i = 0; i <= MAXN; i++)
    {
        if(a[i] > 0)
            return a[i];
    }
}

模板

P3812 【模板】线性基

首先构建线性基

然后从高位往低位,只要能变成1就变成1

因为只要高位有1,就会比高位是0更优,就像二进制下的 1000...(n个0)>0111...(n个1)

第k小

首先我们要改造一下线性基。

我们把线性基改造成每一位相互独立,意思就是对于第i位,线性基上只有一个未知的第i位可能是1。

具体如何改造,就是从高位向低位扫描,对于第i位线性基a[i],对于j<i,如果a[i]的第j位是1,就让a[j]异或上a[i]。

(可以发现,构造线性基的过程类似于高斯消元的消元过程,改造线性基的过程类似于高斯消元的回代过程)

查询的时候,将k进行二进制拆分,对于的1位,就异或对应的线性基。

最终得到的答案是第k小值。

int p[64],cnt;
void rebuild()
{
	for(int i = MAXN; i >= 0; i--)
    {
        for(int j = i - 1; j >= 0; j--)
            if(a[i] & (1LL << j))
                a[i] ^= a[j];
    }
    for(int i = 0; i <= MAXN; i++)
    {
        if(a[i])
            p[cnt++]=d[i];
    }
}

long long query(long long k)
{
    long long ans=0;
    rebuild();
    if(k >= (1LL << cnt))
    	return -1;
    for(int i = 0; i <= MAXN; ++i)
    {
        if(k & (1LL << i))
            ans ^= p[i];
    }
    return ans;
}

练习题目

题单

posted @ 2024-01-27 19:50  wljss  阅读(29)  评论(0编辑  收藏  举报