[题解]BZOJ2460元素
题目描述
给出n个元素,每一个元素有一个数值\(a_i\)和价值\(b_i\)
定义子集\(S\)的价值为\(\sum b[i]\),求\(a\)的异或值不为0的子集中,价值的最大值
分析
一篇有理有据的题解
嗯就是线性基+贪心
2019.10.20update:果然我又回来重新学线性基了。为啥这个那么草率的呀
把所有元素按照\(b[i]\)排序,然后一个个插入线性基中
- 如果可以插入:那么直接插入,并把答案加上当前的\(b[i]\)
- 否则:说明线性基中存在\(d[x]\oplus d[y]\oplus...\oplus d[z]=b[i]\),如果要把\(b[i]\)插进去,必然需要撤销掉之前所选择的一些元素,但由于我们已经按照\(b[]\)排好序了,这样显然是不优的
之前在想会不会从原先的线性基中删去一个可以插入两个新的元素。然后发现这个显然是不可能的
代码
#include<bits/stdc++.h>
#define rep(X,A,B) for(int X=A;X<=B;X++)
#define tep(X,A,B) for(int X=A;X>=B;X--)
#define LL long long
const int N=1000010;
const int M=2000010;
const int maxn=60;
using namespace std;
void read(int &x){
x=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^48);
}
void read(LL &x){
x=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^48);
}
struct nn{
LL num;
int val;
}a[N];
int cmp(nn A,nn B){
return A.val>B.val;
}
int n;
LL d[N];
void READ(){
read(n);
rep(i,1,n)read(a[i].num),read(a[i].val);
sort(a+1,a+n+1,cmp);
}
int INS(LL x){
tep(i,60,0){
if(!((x>>i)&1))continue;
if(!d[i]){
d[i]=x;
return 1;
}
x^=d[i];
}
return 0;
}
int SOLVE(){
int ans=0;
rep(i,1,n)if(INS(a[i].num))ans+=a[i].val;
return ans;
}
int main(){
READ();
printf("%d\n",SOLVE());
return 0;
}