[题解]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;
}
posted @ 2019-04-21 15:02  硫氯  阅读(83)  评论(0编辑  收藏  举报