P4570 [BJWC2011]元素 (线性基)
题意:n个石头 每个石头有a,b两个属性
要求选出一些石头使得没有一个子集的a属性xor和为0 且b属性和最大
题解:线性基例题了.. 好像需要理解一些性质
1.原序列里任一数都可有由线性基xor得到
2.线性基里的数是线性无关的 及没有一个子集xor和为0 (就刚好满足题意了
3.线性基在保证性质1的前提下 数的大小是最少的
于是这个题就把b属性从大到小排序 贪心的如果这个数能插进去就算上贡献
如果某个数插入不进来 那么说明他和之前的插入进来的数 线性相关了 那么之前的数都比他大 那么肯定要前面的数
然后也不会有先插入了一个大的数A 导致较小的两个B,C插入不进来 但B+C的b属性大于A和A后面选的 这种情况
假如这样的话 说明A可以由 B,C这种情况给线性表示 那么你显然可以去掉B,C里面一个与A线性相关的点 然后把A放进来
这样构成一个线性基肯定更优 所以大的数能插就插进来
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; struct node{ ll a; int b; }e[1005]; bool cmp(node A, node B) { return A.b > B.b; } ll val[70]; int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%lld%d", &e[i].a, &e[i].b); sort(e + 1, e + 1 + n, cmp); int ans = 0; for(int i = 1; i <= n; i++) { ll tmp = e[i].a; for(int j = 60; j >= 0; j--) { if(tmp & (1LL << j)) { if(!val[j]) { ans += e[i].b; val[j] = tmp; break; } tmp ^= val[j]; } } } printf("%d\n", ans); return 0; }