线性基的一些基础模版

大神博客:https://blog.csdn.net/a_forever_dream/article/details/83654397

线性基三大性质

1.原序列里面的任意一个数都可以由线性基里面的一些数异或得到

2.线性基里面的任意一些数异或起来都不能得到0

3.线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的

插入操作:

void add(ll x)
{
    for(int i=50;i>=0;i--)
    {
        if(x&(1ll<<i))//注意,如果i大于31,前面的1的后面一定要加ll
        {
            if(d[i])x^=d[i];
            else
            {
                d[i]=x;
                break;//记得如果插入成功一定要退出. 
            }
        }
    }
    //插入失败
}

 

求最大值:

完整的说,是如何求在一个序列中,取若干个数,使得它们的异或和最大。
首先构造出这个序列的线性基,然后从线性基的最高位开始,假如当前的答案异或线性基的这个元素可以变得更大,那么就异或它,答案的初值为0

要优先使最高位尽可能大

ll getmax()
{
    ll anss=0;
    for(int i=50;i>=0;i--)//记得从线性基的最高位开始
        if((anss^d[i])>anss)anss^=d[i];
    return anss;
}

 

求第k小的值

void work()//处理线性基
{
    for(int i=1;i<=60;i++)
        for(int j=1;j<=i;j++)
            if(d[i]&(1<<(j-1)))d[i]^=d[j-1];
}
ll k_th(ll k)
{
    if(k==1&&tot<n)return 0;//特判一下,假如k=1,并且原来的序列可以异或出0,就要返回0,tot表示线性基中的元素个数,n表示序列长度
    if(tot<n)k--;//类似上面,去掉0的情况,因为线性基中只能异或出不为0的解
    work();
    ll ans=0;
    for(int i=0;i<=60;i++)
        if(d[i]!=0)
        {
            if(k%2==1)ans^=d[i];
            k/=2;
        }
    return ans;
}

 

转载于:https://www.cnblogs.com/smallhester/p/11415311.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值