异或线性基学习笔记

更好的阅读体验

前言

本文的线性基指异或线性基。
由于作者太菜了本文的语言不会特别规范。

简介

线性基简称基,它是一个数的集合,并且每个序列都拥有至少一个线性基。
线性基有三个性质:

  1. 线性基中的几个数异或后不能得到 0 0 0
  2. 线性基中的数在异或后能得到原序列中的所有数。
  3. 线性基在保证前两个性质时,会使得基内的个数最少。

基本操作

我们用数组 p p p 表示 { a i − 1 } \{a_{i - 1}\} {ai1} 的线性基。
p i p_i pi 的二进制最高位是第 i + 1 i + 1 i+1 位。

插入

如果 x x x 的第 i i i 位是 1 1 1,就必须要选 p i p_i pi,否则不选。

必须选时,如果没有 p i p_i pi,那么我们就让 p i ← x p_i \gets x pix,并结束。
否则 x ← x ⊕ p i x\gets x\oplus p_i xxpi

void insert(int x){
    for(int i = 60; ~i; i--)
    if(x & (1LL << i))
        if(!p[i])return void(p[i] = x);
        else x ^= p[i];
}

最大值

我们的二进制最高位是依次递减的。
a n s ans ans 表示目前的最大值。

那么如果 a n s ans ans 的第 i i i 位是 0 0 0,那么选 p i p_i pi 一定不劣,因为 2 k > ∑ i = 0 k − 1 2 i 2^k > \sum_{i=0}^{k-1}2^i 2k>i=0k12i

int xormax(){
    int ans = 0;
    for(int i = 60; ~i; i--)
        ans = max(ans, ans ^ p[i]);
    return ans;
}

第 k 小

如果我们选择高位后不会对低位影响,那么我们就可以像 BST 求第 k k k 小一样了。
所以我们要尽可能把 p i p_i pi 除了第 i i i 的其他位去掉。
形如:
10001000
01100000
00010001
00000100
虽然不能全部去掉,但是我们的目的已经达到了。

int kth(int k){
    if(f)return 0;
    for(int i = 0; i <= 60; i++)
        for(int j = i - 1; ~j; j--)
            if(p[i] & (1LL << j)) p[i] ^= p[j-1];
    int ans = 0;
    for(int i = 0; i <= 60; i++)
        if(p[i]){
            if(k & 1)ans ^= p[i];
            k >>= 1;
        }
    if(k)return -1; 
    return ans;
}

复杂度

时空复杂度(单次): O ( log ⁡ n ) O(\log n) O(logn)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值