线性基
vector<ull> B; void insert(ull x) { for (auto b : B) x = min(x, b ^ x); for (auto &b : B) b = min(b, b ^ x); if (x) B.push_back(x); }
这样构造产生的性质:
- 产生的线性基可以表示原集里面xor产生的所有值
- 线性基里面的值不能被其他元素xor产生
- 每个元素的最高有效位各不相同,
- 如果某一位是一个元素的最高有效位,则其他元素在这一位均为 0
- 判断某个值是否可以产生, 就这个值去 假的insert一下 看他是不是0即可
- 第K大的xor值 直接 对线性基排一个序列 ,然后二进制那个求就行了
- 如果构造的线性基比原集合小,说明原集合可以异或出 0 ,那么我们需要将 K 减去 1 。
-
sort(B.begin(), B.end()); ull ans = 0; if (B.size() < n) k--; for (auto b : B) { if (k & 1) ans ^= b; k >>= 1; } if (k == 0) cout << ans << endl; else cout << -1 << endl;
- 线性基的交集,没有看懂
inline bool insert(ll x) { for (int i=62;i>=0;i--) if (x>>i)//为什么可以不写x&(1<<i)?,因为我们每次x的最高位都是因为x^=p[i]变为0,这样也能判断最高位 if (p[i]) x^=p[i];//如果第i位这个线性基有,同上方的p[6] else { p[i]=x; return 1;//1代表插入成功 } return 0; //0代表这个数x能被线性基表示,0需要特判 } LinearBasis Merge(LinearBasis A,LinearBasis B) { LinearBasis All , C , D; All.clear(); C.clear(); D.clear(); for (int i = 60;i >= 0;i--) { All.basis[i] = A.basis[i]; D.basis[i] = 1ll << i; } for (int i = 60; i >= 0; i--) { if (B.basis[i]) { ll v = B.basis[i] , k = 0; bool can = true; for (int j = 60; j >= 0; j--) { if (v & (1ll << j)) { if (All.basis[j]) { v ^= All.basis[j]; k ^= D.basis[j]; } else { can = false; All.basis[j] = v; D.basis[j] = k; break; } } } if (can) { ll v = 0; for (int j = 60; j >= 0; j--) { if (k & (1ll << j)) { v ^= A.basis[j]; } } C.insert(v); } } } C.build(); return C; }