(数论二)浅谈线性基

​ 前两天作了一套题,有一道线性基的模版题没出,觉得有必要学一手线性基了…

一.线性基是什么?

​ 线性基其实就是一个集合。假设一个普通的集合为A,它的线性基集合B是A的一个子集。B中所有子集的异或和组成的集合等价于A中所有子集的亦或和组成的集合(除0外)。

二.线性基有什么性质:

​ 1.若一个数x能被线性基集合中某个子集的异或和得到,该子集唯一

​ 2.线性基集合中任意一个子集的异或和不为0

​ 3.线性基集合中每个元素的最高位互不相同

​ 4.若线性基集合是满的(也就是说最高位是1~n位的数都存在),那么它的异或集合是【1, 2^n - 1】

三.关于线性基的代码实现:

​ 我们用p数组存储线性基的元素

​ (1)关于线性基中元素的插入

​ 我们要插入一个数x,需要从高到低枚举所有位,若x&当前位 != 0,若当前位不存在线性基元素,则将x当作线性基的当前位元素,否则x异或当前位元素,直到x为0或将x添加到线性基中

​ 代码如下 :

void addx (ll x) {
    for (ll i = 62; i >= 0; i--) {	//long long型的最大值为2^63 - 1,因此是0~62
        if (x >> i & 1) {
            if (!p[i]) {
                p[i] = x;
                break;
            }
            x ^= p[i];
        }
    }
    return;
}

​ (2)关于求最大异或和:

​ 初始化res = 0,从高到低遍历位数,若res ^ p[i]大于res就更新res,最后res即为线性基所能得到的最大异或和

​ 代码如下:

ll getmax() {
    ll res = 0;
    for (ll i = 62; i >= 0; i--) {
        if (res < (res ^ p[i])) res ^= p[i];
    }
    return res;
}

​ (3)关于求异或t后的最大异或和:

​ 同上一样,只需要初始化res = t即可。

​ 代码如下:

ll getmaxt() {
    ll res = t;
    for (ll i = 62; i >= 0; i--) {
        if (res < (res ^ p[i])) res ^= p[i];
    }
    return res;
}

​ (4)关于求最小异或和:

​ 最小值就是线性基中位数由低到高第一个存在的p[i]

​ 代码如下:

ll getmin () {
    for (ll i = 0; i <= 62; i++) {
        if (p[i]) return p[i];
    }
    return 0;
}

​ (5)关于求异或集合中的第k小值

​ 需要把线性基集合中的元素改为除了最高位为1,其余位为0的形式。也就是说,若j<i且p[i]中第j位是1,就p[i] ^ p[j]

​ 我们对k进行二进制拆分,若第i位为1,就异或p[i],最终得到的答案就是第k小的异或值

​ 代码如下:

int tot = -1;
void build () {
    for (ll i = 62; i >= 0; i--) {
        for (ll j = i - 1; j >= 0; j--) {
            if (p[i] >> j & 1) p[i] ^= p[j];
        }
    }
    for (ll i = 0; i <= 62; i++) {
        if (p[i]) g[++tot] = p[i];
    }
}

ll query (ll k) {
	//若原数组中存在元素0,则此时需要k--
    if (k >= (1LL * tot)) return -1;
    ll res = 0;
    for (ll i = tot; i >= 0; i--) {
        if (k >> i & 1) res ^= g[i];
    }
    return res;
}

四. 线性基能求解什么问题?

​ (1). 给出一个数组,问一个数能否由数组中的元素异或得到

​ (2).给出一个数组,问数组中全部子集异或和组成的集合中,第k小的数是多少

​ (3).给出一个数组和一个数t,问数组全部子集的异或和(可重复)按从小到大排序,第一个等于t的下角标是多少?

​ (4).给出一个可重集合和k,等概率选一个子集A,得到A的异或和x,问x^k的数学期望值是多少?

​ (5).给出一个连通无向图(n个点m条边,每个边有一个权值),问从起点走到终点异或和最小的值是多少?

​ 以上就是总结的线性基的基础,遇到异或问题,可以首先考虑能否使用线性基,就酱~

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

猜你喜欢

转载自blog.csdn.net/Ivan_zcy/article/details/83186749