P4570 [BJWC2011]元素

题意:给出n个矿石,每个矿石有编号和价值

   让我们求出如何融合矿石,才能使最后的价值最大(要满足所选择的矿石的编号异或之后不为0);

思路:根据线性基的性质

  • 快速查询一个数是否可以被一堆数异或出来
  • 快速查询一堆数可以异或出来的最大/最小值
  • 快速查询一堆数可以异或出来的第k大值
  • 原数列里的任何一个数都可以通过线性基里的数异或表示出来
  • 线性基里任意一个子集的异或和都不为0
  • 一个数列可能有多个线性基,但是线性基里数的数量一定唯一,而且是满足性质一的基础上最少的

根据第五第六条性质,因为线性基里面的数量是一定的,也就是说,我们选择的矿石数量是不变的

所以,我们贪心优先选择价值最大的矿石,即:将矿石价值从大到小排序,然后记录下被选择的矿石的价值,最后输出即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn=1e3+10;
 5 ll p[70];
 6 struct node
 7 {
 8     ll id;
 9     ll sum;
10 }a[maxn];
11 bool cmp(node x,node y)
12 {
13     return x.sum>y.sum;
14 }
15 int Insert(ll k) {
16     for(ll i=64;i>=0;i--) {
17         if(!(k&(1LL<<i))) continue;
18         if(!p[i]){
19             p[i]=k;
20             return 1;
21         }
22         k ^= p[i];
23     }
24     return 0;
25 }
26 int main()
27 {
28     int n;
29     scanf("%d",&n);
30     for(int i=1;i<=n;i++){
31         scanf("%lld%lld",&a[i].id,&a[i].sum);
32     }
33     sort(a+1,a+1+n,cmp);
34     ll ans=0;
35     for(int i=1;i<=n;i++){
36         if(Insert(a[i].id)){
37             ans+=a[i].sum;
38         }
39     }
40     printf("%lld\n",ans);
41     return 0;
42 }

 

posted @ 2021-01-25 15:05  古比  阅读(52)  评论(0编辑  收藏  举报