题目描述:

每个矿石有序号和魔力值,每个矿石最多使用一次,且多个矿石序号不能异或为0的前提下,问最多可以得到多少魔力值

题解:

异或运算的最终结果只和用于运算的数的各位上1的数量有关,与各数字运算的顺序无关
所以直接先使用魔力值最大的石头就行
按照魔力值从大到小排列,insert成功的就记录魔力值,失败的就跳过

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
   return s*w;
}
const int maxn=1030;
ll a[maxn];
int L=60;
struct node{
    ll num,mag;
}c[maxn];
bool insert(ll x){
    for(int j=L;j>=0;--j){//从最高位开始看
        if((x&(1ll<<j))==0) continue;

        if(a[j]){//若如主元j已经存在,用a[j]消去x的第j位然后继续
            x ^= a[j];
            continue;
        }   

        //让x当主元j,需要先用第k(k<j)个主元消去x的第k位
        for(int k=j-1;k>=0;k--){
            if(x & (1ll<<k)) x ^= a[k];
        }
        //接着用x去消掉第k(k>j)个主元的第j位
        for(int k=L;k>j;k--){
            if(a[k] & (1ll<<j)) a[k] ^= x;
        }
        a[j] = x;
        return 1; 
    }
    return 0;
}
bool cmp(node a,node b)
{
    return a.mag>b.mag;
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>c[i].num>>c[i].mag;
    }
    sort(c+1,c+1+n,cmp);
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        bool w=insert(c[i].num);
        if(w==1)
        {
            ans+=c[i].mag;
        } 
    }
    cout<<ans;
}