一、题目
二、解法
首先考虑判断一个集合是否有异或值为 0 0 0的子集,我们可以把就考虑加入一个数之后判断,先维护出原先的数的线性基,然后再看这个数是否能插入到线性基里面,就是它能不能被前面的数组合出来。
后面的做法需要对线性基有更深的理解,可以康康这个博客
我们把第二维从大到小排序,因为无论如何构造线性基内元素个数都是一定且最小的,然后我们能插入线性基则加入贡献,因为如果不选就会由后面更小的来替换,而且对线性基(其他的决策)没影响。
#include <cstdio>
#include <algorithm>
using namespace std;
const int M = 1005;
#define int long long
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,ans,p[70];
struct node
{
int a,b;
bool operator < (const node &r) const
{
return b>r.b;
}
}a[M];
bool ins(int x)
{
for(int i=59;i>=0;i--)
{
if(!(x>>i)) continue;
if(!p[i]) {p[i]=x;break;}
x^=p[i];
}
return x;
}
signed main()
{
n=read();
for(int i=1;i<=n;i++)
a[i]=node{read(),read()};
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
if(ins(a[i].a))
ans+=a[i].b;
printf("%lld\n",ans);
}