性质
- 线性基的元素能通过相互异或,得到原序列的元素的所有相互异或得到的值。也可以得到原序列的任意一个数。
- 线性基是满足性质1的最小集合。
- 线性基没有异或和为 0 的子集。
- 线性基中每个元素的异或方案唯一,也就是说,线性基中不同的异或组合异或出的数都是不一样的。
- 线性基中每个元素的二进制最高位互不相同。
ll d[64]; void add(ll x) { for (int i = 60; ~i; --i) { if (x & (1ll << i)) { // 如果x此位有 if (d[i]) // 如果本位此前已存值 x ^= d[i]; // 已有的消除 else { d[i] = x; // 直接存储 break; } } } }
求最大值
求序列中的数所能异或出来的最大值
ll solve() { ll ans = 0; for (int i = 60; ~i; --i) { if (ans ^ d[i] > ans) ans ^= d[i]; } return ans; }
求最小值
判断有没有add失败,如果有,就是0,否则是d[0]
求第k小的值
ll d[64], n, tot; void add(ll x) { for (int i = 60; ~i; --i) { if (x & (1ll << i)) { // 如果x此位有 if (d[i]) // 如果本位此前已存值 x ^= d[i]; // 已有的消除 else { d[i] = x; // 直接存储 break; } } } } void work() { //处理线性基 for (int i = 1; i <= 60; i++) for (int j = 1; j <= i; j++) if (d[i] & (1ll << (j - 1))) d[i] ^= d[j - 1]; } ll kTh(ll k) { if (k == 1 && tot < n) return 0; //特判一下,假如k=1,并且原来的序列可以异或出0,就要返回0,tot表示线性基中的元素个数,n表示序列长度 if (tot < n) k--; //类似上面,去掉0的情况,因为线性基中只能异或出不为0的解 work(); ll ans = 0; for (int i = 0; i <= 60; i++) if (d[i] != 0) { if (k % 2 == 1) ans ^= d[i]; k /= 2; } }