板子:线性基

简述

线性相关:可以通过一些元素异或出集合中其它元素。

线性基的一些性质:
- 线性基内所有元素线性无关
- 对于原集合任意元素异或的值域和线性基任意元素异或的值域相同
- 线性基的个数就是二进制下位的个数
- 线性基a[i]如果存在,则满足第i位是1,且前面的位都是0

不用太在意如何求出的线性基

一些操作

  • 最大值查询可以询问当前元素,只需要把ret改成当前元素即可

  • 最小应该也可以用类似的贪心方法

对于第K小的判定的理解

对于第i位的元素,如果选择,将会带来2^i个较大元素,所以如果K第i位有元素,就需要选择当前线性基

注意

  • 第一位应该是第0位
  • 注意位运算要对1ll做
  • 线性基要求不能异或出0,所以需要特判0,在插入的时候判断时候有0元素

论线性基和二进制trie的区别:

都是处理异或运算的手段

二进制trie是查找当前元素与一堆元素里面某一元素的最大异或和;

线性基是查找一堆元素任意选取一个子集的最大异或和

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int oo=60;/=log2n
struct LinearBasis{
    static const int maxn=65;
    bool o;//o=0表示没有0 
    int cnt;
    LL d[maxn],p[maxn];
    void Initial()
    {
        cnt=o=0;
        memset(d,0,sizeof(d));
        memset(p,0,sizeof(p));
    }
    bool Insert(LL val)//在原集合中插入val 
    {
        for(int i=oo;i>=0;i--)
        {
            if(val&(1ll<<i))
            {
                if(!d[i])
                {
                    d[i]=val;
                    break;
                }
                val^=d[i];
            }
        }
        if(!val)o=1;
        return val;//成功则返回true 
    }
    LL query_max()//贪心策略:从大往小只要当前元素更大,则异或
    {
        LL ret=0;
        for(int i=oo;i>=0;i--)
            ret=max(ret,ret^d[i]);
        return ret; 
    }
    LL query_min()
    {
        if(o)return 0;
        for(int i=0;i<=oo;i++)
            if(d[i])
                return d[i];
        return 0;
    }
    void rebuild()//这应该是还原成高斯消元后的结果?需要在找第K大的时候使用 
    {
        for(int i=oo;i>=0;i--)
            for(int j=i-1;j>=0;j--)
                if(d[i]&(1ll<<j))
                    d[i]^=d[j];
        for(int i=0;i<=oo;i++)
            if(d[i])p[cnt++]=d[i];
    }
    LL Kth(LL k)//查询第K小的元素 
    {
        LL ret=0;
        if(o)k--;
        if(k>=(1ll<<cnt))//一共有2^cnt-1个元素 
            return -1;
        for(int i=oo;i>=0;i--)//如果K的第i位有元素,则异或 
            if(k&(1ll<<i))ret^=p[i];
        return ret;
    }

}lb;
typedef LinearBasis L_B;
L_B Merge(const L_B &n1,const L_B &n2)//两个线性基合并:暴力插入
{
    L_B ret=n1;
    for(int i=oo;i>=0;i--)
        if(n2.d[i])ret.Insert(n2.d[i]);
    return ret;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值