bzoj2460元素(线性基,贪心)
题目大意:
给定\(n\)个二元组\((a,b)\),求一个最大的\(\sum b\)的集合,满足这个集合的任意子集的\(a\)的\(xor\)值不为0
这道题需要一个线性基的性质:
线性基的任何非空子集的\(xor\)值不为0
那么我们对于题目中对a的要求,只需要维护一个线性基即可。
那如何保证\(\sum b\)最大呢....我们可以按照b排序,然后依次插入线性基,如果经过插入操作后\(a[i].a\)不为0,就说明他被加入了线性基,那么就可以将他的\(a[i].b\)加入答案
至于贪心的正确性....我也不是很会证明...大致可以理解为权值大的应该尽量早加,如果将当前点加入必须要删除之前的点的话,那一定是不优的,因为我们提前按照权值排过序
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 110;
ll base[maxn],n,k;
struct Node{
ll id,val;
};
Node a[1010];
ll ans;
bool cmp (Node a,Node b)
{
return a.val>b.val;
}
int main()
{
n=read();
for (int i=1;i<=n;i++) a[i].id=read(),a[i].val=read();
sort(a+1,a+1+n,cmp);
for (int i=1;i<=n;i++)
{
for (ll j=63;j>=0;j--)
{
if(a[i].id & (1LL << j))
{
if (!base[j])
{
base[j]=a[i].id;
break;
}
a[i].id^=base[j];
}
}
if (a[i].id>0) ans+=a[i].val;
}
cout<<ans;
return 0;
}