线性基(解决子集异或和问题)
适用:解决集合异或和问题(第k小异或,最大异或,能否异或和组成给定的数)
用途:主要给个S集合,能通过动态插入每个数得到大小为log{max ai}的线性基B,而B中的所有情况异或和都唯一对应于S中的每个数
注意:线性基中没有异或和为0的子集,也就是说当线性基集合小于S时,证明在S中有些集合异或和为0;
模板题:https://vjudge.net/problem/SGU-275
题意:求能异或和最大的值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int M=60; struct LB{ ll a[M+2]; void init(int n){ for(int i=0;i<=M;i++) a[i]=0; } void Insert(ll t){ // 逆序枚举二进制位 for (int j = M; j >= 0; j--){ // 如果 t 的第 j 位为 0,则跳过 if (!(t & (1ll << j))) continue; // 如果 a[j] != 0,则用 a[j] 消去 t 的第 j 位上的 1 if (a[j]) t ^= a[j]; else{ // 找到可以插入 a[j] 的位置 // 用 a[0...j - 1] 消去 t 的第 [0, j) 位上的 1 // 如果某一个 a[k] = 0 也无须担心,因为这时候第 k 位不存在于线性基中,不需要保证 t 的第 k 位为 0 for (int k = 0; k < j; k++) if (t & (1ll << k)) t ^= a[k]; // 用 t 消去 a[j + 1...L] 的第 j 位上的 1 for (int k = j + 1; k <= M; k++) if (a[k] & (1ll << j)) a[k] ^= t; // 插入到 a[j] 的位置上 a[j] = t; // 不要忘记,结束插入过程 return; } // 此时 t 的第 j 位为 0,继续寻找其最高位上的 1 } // 如果没有插入到任何一个位置上,则表明 t 可以由 a 中若干个元素的异或和表示出,即 t 在 span(a) 中 } ll getmax(){ ll ans=0; for(int i=M;i>=0;i--) ans^=a[i]; return ans; } }lb; int main(){ int n; scanf("%d",&n); lb.init(n); for(int i=1;i<=n;i++){ ll x; scanf("%lld",&x); lb.Insert(x); } printf("%lld\n",lb.getmax()); return 0; }
学习粗:https://oi.men.ci/linear-basis-notes/