跳转至

线性基

基本概念

请自学高中的线性代数,并基本掌握这些内容:

我们从代数上还可以说,多个标量捆绑在一起构成了向量()

  • 向量定义
  • 代数表示
  • 基本运算(代数与几何上)
    • 数乘:乘以标量 \(k\),若为负数则方向相反,其长度变为原来 \(|k|\) 倍。
    • 加(减)法:平行四边形法则。
    • 其实向量还有内积和叉积,但与本节关系不大,暂略。
  • 平面、空间向量基本定理,即基底的思想

  • 线性空间:由一群可缩放和相加的数学实域(如实数甚至是函数)所构成的特殊集合,其特殊之处在于缩放(e.g. 数乘)和相加后仍属于这个集合(封闭)。不严谨的讲,只要能满足这两种运算封闭的数学对象(广义的向量)构成的集合,都可以称作 “线性空间”。

  • 线性组合:即向量与数乘、加法的任意组合。
  • 线性无关:线性空间的一组向量中,若没有向量可由该组中有限个其他向量的线性组合所表示,则称它们线性无关或线性独立。比如一组基底就是线性无关的。

实数线性基

二维与三维的实数线性基,其实就是平面空间和立体空间的一组基底。

异或空间线性基

我们知道,对于每一个二进制位来说,异或是模2意义下的封闭加法运算。根据取模意义下的乘法,我们也可以得出其在模2意义下运算封闭。这是什么?这是线性空间!!!

那么,若把数字的每一个二进制位看成一个标量,则数字便是把它们“捆”起来的一个“向量”,其二进制位个数类似于维数。

用处

  • 快速查询一个数是否可以被一堆数异或出来
  • 快速查询一堆数可以异或出来的最大/最小值
  • 快速查询一堆数可以异或出来的第k大值
  • 查询一个数异或一堆数中任意个的最大值

求法

高斯消元求线性基

#include <bits/stdc++.h>
using ull = unsigned long long;
const int MAXN = 1e5 + 5;

ull deg(ull num, int deg) { return num & (1ull << deg); }

ull a[MAXN];

int main() {
  int n;
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) scanf("%llu", &a[i]);
  int row = 1;
  for (int col = 63; ~col && row <= n; --col) {
    for (int i = row; i <= n; ++i) {
      if (deg(a[i], col)) {
        std::swap(a[row], a[i]);
        break;
      }
    }
    if (!deg(a[row], col)) continue;
    for (int i = 1; i <= n; ++i) {
      if (i == row) continue;
      if (deg(a[i], col)) {
        a[i] ^= a[row];
      }
    }
    ++row;
  }
  ull ans = 0;
  for (int i = 1; i < row; ++i) {
    ans ^= a[i];
  }
  printf("%llu\n", ans);
  return 0;
}

贪心法求线性基

贪心+消元的动态方法*

增删改查

验证线性相关

只需要看能否最终插入线性基即可。

从中取任意多个数,与某个数异或的最值

贪心

能异或出的第 k 大值

先消成最简形式,即主元有且仅出现一次。

将k的二进制形式表出,在线性基中只考虑有值的位,直接根据二进制位选择即可。

https://www.luogu.com.cn/problem/P4151