线性基总结(其实就是我的模板)
想知道线性基直接看大佬的https://blog.sengxian.com/algorithms/linear-basis, 我就是弄下我常用的操作。
定义
学过线代里面的“基向量”,基向量说的就是一组可以表示整个空间的向量。比如在三维空间中一个基向量就是(1,0,0) (0,1,0) (0,0,1)。线性基的定义也类似,给你一个数组a[ ],它的线性基就是一组可以表示数组a中任意一个数的一个数组p[ ]。这个表示的意思就和前面的基向量表示的意思类似,是通过p中几个元素的异或得到a中的任意一个元素。
性质
1 原序列里面的任意一个数都可以由线性基里面的一些数异或得到
2 线性基里面的任意一些数异或起来都不能得到0
3 线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的
#include<bits/stdc++.h> #define mp make_pair #define met(a, b) memset(a, b, sizeof(a)) #define ll long long using namespace std; ll p[70], newp[70], cnt; void getp(ll x){ //构建 for(ll i = 63; i >= 0; i--){ if(!(x>>i)) continue; if(!p[i]){ p[i] = x; break; } x ^= p[i]; } } ll getmax(){ //求异或最大值 ll ans = 0; for(int i = 63; i >= 0; i--){ if((ans ^ p[i]) > ans) ans ^= p[i]; } return ans; } ll getmin(){ //求异或最小值 for(int i = 0; i <= 63; i++){ if(p[i]) return p[i]; } return 0; } bool judge(ll x){ //判断x是不是数组a中的 for(ll i = 63; i >= 0; i--){ if(x>>i) x ^= p[i]; if(!x) return 1; } return 0; } void rebuild(){ //求第k小的准备工作 cnt = 0; for(ll i = 63; i >= 0; i --){ for(ll j = i - 1; j >= 0; j --) if(p[i] & (1 << j)) p[i] ^= p[j]; } for(ll i = 0; i <= 63; i ++){ if(p[i]) newp[cnt++] = p[i]; } } ll getans(ll k){ //求第k小 if(k >= (1ll << cnt)) return -1; ll ret = 0; for(ll i = 63; i >= 0; i --){ if(k & (1ll << i)) ret ^= newp[i]; } return ret; } int main(){ int n; cin >> n; for(int i = 1; i <= n; i++){ ll x; cin >> x; getp(x); } rebuild(); int m; cin >> m; while(m--){ ll k; cin >> k; if(n != cnt) k--; //注意这个 cout << getans(k) << endl; } return 0; }