题目:


  给定n个矿石的编号和魔力值,让你选出一些矿石,这些矿石的id异或起来不能是0,而且总的魔力值最大,输出最大的魔力值

Input

第一行包含一个正整数N,表示矿石的种类数。
接下来 N行,每行两个正整数Numberi 和 Magici,表示这种矿石的元素序号和魔力值。

对于全部的数据:N ≤ 1000,Numberi ≤ 10^18,Magici ≤ 10^4。

Output

仅包一行,一个整数:最大的魔力值

Sample Input

3
1 10
2 20
3 30

Sample Output

50

解题思路:


看到XOR一般就要想到线性基,这里只需要用到最基础的线性基即可,不需要求异或出来的第k小的数

一般的线性基模版每当p[j]已经有数时,a[i]^=p[j],直到a[i]可以填入,这样的话实际上最后能填入的那个非零的a[i]是由多个原a[i]异或出来的。

将矿石的属性存入结构体数组中,按照魔力值从大到小排序,从魔力值大的矿石开始遍历,用其id构造行阶梯矩阵,如果可以填入(最终异或得到的a[i].id不为0),说明最初的a[i].id与之前选定的矿石中的部分矿石的a[i].id异或起来不为0,将其value值加入结果中,且整个行阶梯矩阵本身就线性无关的,异或起来非0。这样根据贪心的思想,最终结果记录的就是最大的魔力值。

ac代码:


 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000+10;
const int max_base=60;
struct node{
    ll id;
    ll value;
    friend bool operator <(node a,node b)
    {
        return a.value>b.value;
    }
}a[maxn];
ll n,p[max_base+3];
ll solve()
{
    ll ans=0;
    for(int i=0;i<n;i++)
    {
        for(int j=max_base;j>=0;j--)
        {
            if(a[i].id>>j&1)
            {
                if(p[j])
                    a[i].id^=p[j];
                else
                {
                    p[j]=a[i].id;
                    break;
                }
            }
        }
        if(a[i].id)
            ans+=a[i].value;
    }
    return ans;
}
int main()
{
    scanf("%lld",&n);
    for(int i=0;i<n;i++)
        scanf("%lld %lld",&a[i].id,&a[i].value);
    sort(a,a+n);
    printf("%lld\n",solve());
    return 0;
}