线性基整理

线形基(来自OI Wiki):

线性基是向量空间的一组基,通常可以解决有关异或的一些题目。

通俗一点的讲法就是由一个集合构造出来的另一个集合,它有以下几个性质:

  • 线性基的元素能相互异或得到原集合的元素的所有相互异或得到的值。

  • 线性基是满足性质 1 的最小的集合。

  • 线性基没有异或和为 0 的子集。

  • 线性基中每个元素的异或方案唯一,也就是说,线性基中不同的异或组合异或出的数都是不一样的。

  • 线性基中每个元素的二进制最高位互不相同。

对于线性基的数组a[],a[i]表示最高位的1在第i位的值

构造线性基的方法:对原集合的每一个数p转化为二级制,从高位向低位扫,对于第i位是1,若a[i]==0,令a[x]=p,扫描结束;

若a[i]!=0,令p^=a[i],继续扫描。

代码:


void insert(int p) {
    //具体从最高位多少开始扫描,视具体情况而定
    for(int i=30;i>=0;i--) {
        //若i>31,使用(1LL)<<i
        if(p&1<<i){
            if(!a[i]) {
                a[i]=p;
                break;
            }
            p^=a[i];
        }
    }

}

 通过上面插入过程,我们可以知道对一个数判断其是否可以被异或出来,如果成功插入则不可,否则可以。

线性基模板:

//插入
void insert(int p) {
    //具体从最高位多少开始扫描,视具体情况而定
    for(int i=30;i>=0;i--) {
        //若i>31,使用(1LL)<<i
        if((p>>i)&1){
            if(!a[i]) {
                a[i]=p;
                break;
            }
            p^=a[i];
        }
    }

}
//判断是否可以由原集合某些子集异或得到
bool check(int x) {
    for(int i=30;i>=0;--i) {
        if((x>>i)&1) {
            if(!a[i]) return 0;
            x^=a[i];
        }
    }
    return 1;
}
//求最大值
int get_max() {
    int ans=0;
    for(int i=30;i>=0;--i) ans=max(ans,ans^a[i]);
    return ans;
}
//求最小值
int get_min() {
    int ans=0;
    for(int i=0;i<=30;++i) if(a[i]) return a[i];
}
//求第k小的值,对于每一个a[i],
//枚举 j = 1->i
//如果 a[i]的第j位为1,那么d[i]异或d[j−1]。
//然后对k转化为二进制,如果k第i为1,res^=a[i]
ll get_kth(ll k) {
    //处理线性基
    for(int i=1;i<=60;i++)
        for(int j=1;j<=i;j++)
            if(a[i]&(1LL<<(j-1))) a[i]^=a[j-1];
    ll res=0;
    for(int i=1;i<=60;i++) {
        if(a[i]) {
            if(k%2) ans^=a[i];
            k/=2;
        }
    }
    return res;
}
//两个线性基合并 修改一下插入函数 inse(int *a,int x)
void combine(int *a,int *b) {
    for(int i=30;i>=0;i--) {
        if(b[i]) inse(a,b[i]);
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值