线性基: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;
}