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
",ans);

	return 0;
}
原文地址:https://www.cnblogs.com/SovietPower/p/9289307.html