博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

BZOJ.2460.[BeiJing2011]元素(线性基 贪心)

题目链接

线性基:https://blog.csdn.net/qq_36056315/article/details/79819714。


\(Description\)

求一组矿石,满足其下标异或和不为0,且价值和最大。

\(Solution\)

按价值从大到小依次插入线性基,这样最后得到的集合就是价值和最大的了。

贪心策略简单证明(参考:https://www.cnblogs.com/acmsong/p/7508022.html):
假设当前选取的集合\(S\)价值为\(\{v1,v2,...,vn\}\),标号为\(\{id1,id2,...,idn\}\)。所有物品中价值最大的为\(vMax\)\(idMax\)),且当前集合中不包含\(vMax\).
那么\(vMax\)一定可以替换掉\(S\)中的某个元素,使得价值和更大。
如果不能直接插入\(vMax\),说明\(S∪\{1\}\)变得线性相关了,即\(S\)中一定存在一个子集,其下标的\(Xor\)和等于\(idMax\)

\[id[x1]^{\wedge}id[x2]^{\wedge}...^{\wedge}id[xn]=id[Max] \]

然后\(id[Max]\)可以把任意一个元素替换掉,假设是\(x1\),那么两边同时异或\(id[Max]^{\wedge}id[x1]\)

\[id[Max]^{\wedge}id[x2]^{\wedge}...^{\wedge}id[xn]=id[x1] \]

这样就可以把\(id[x1]\)线性表示出来。而\(S\)中如果不加\(id[x1]\)的话是一定表示不出\(id[x1]\)的,因为\(S\)中异或和不为\(0\)(左边异或掉\(id[x1]\)是不等于\(id[x1]\)的)。
所以替换后的线性基和之前是等价的。

用拟阵能证,但是找不到啥详细的证明,我也没拿它证过啥别东西。。

x&(1ll<<i)的话别忘了1ll...


#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=1005;

LL base[69];
struct Node{
	LL id; int val;
	bool operator <(const Node &x)const{
		return val>x.val;
	}
}A[N];

inline LL read()
{
	LL now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}

int main()
{
	int n=read();
	for(int i=1; i<=n; ++i) A[i].id=read(), A[i].val=read();
	std::sort(A+1,A+1+n);
	int ans=0;
	for(int i=1; i<=n; ++i)
	{
		LL now=A[i].id;
		for(int j=60; ~j; --j)
			if(now&(1ll<<j))
				if(base[j]) now^=base[j];
				else {base[j]=now; break;}
		if(now) ans+=A[i].val;
	}
	printf("%d\n",ans);

	return 0;
}
posted @ 2018-07-10 15:26  SovietPower  阅读(138)  评论(2编辑  收藏  举报