题目:
给定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;
}