1. 程式人生 > >【bzoj 2460 [BeiJing2011]元素】

【bzoj 2460 [BeiJing2011]元素】

題意:
 相傳,在遠古時期,位於西方大陸的 Magic Land 上,人們已經掌握了用魔
法礦石煉製法杖的技術。那時人們就認識到,一個法杖的法力取決於使用的礦石。
一般地,礦石越多則法力越強,但物極必反:有時,人們為了獲取更強的法力而
使用了很多礦石,卻在煉製過程中發現魔法礦石全部消失了,從而無法煉製
出法杖,這個現象被稱為“魔法抵消” 。特別地,如果在煉製過程中使用超過
一塊同一種礦石,那麼一定會發生“魔法抵消”。
後來,隨著人們認知水平的提高,這個現象得到了很好的解釋。經過了大量
的實驗後,著名法師 Dmitri 發現:如果給現在發現的每一種礦石進行合理的編
號(編號為正整數,稱為該礦石的元素序號),那麼,一個礦石組合會產生“魔
法抵消”當且僅當存在一個非空子集,那些礦石的元素序號按位異或起來
為零。 (如果你不清楚什麼是異或,請參見下一頁的名詞解釋。 )例如,使用兩
個同樣的礦石必將發生“魔法抵消”,因為這兩種礦石的元素序號相同,異或起
來為零。
並且人們有了測定魔力的有效途徑,已經知道了:合成出來的法杖的魔力
等於每一種礦石的法力之和。人們已經測定了現今發現的所有礦石的法力值,
並且通過實驗推算出每一種礦石的元素序號。
現在,給定你以上的礦石資訊,請你來計算一下當時可以煉製出的法杖最多
有多大的魔力。

3
1 10
2 20
3 30
輸出

50

題意懂了就好了,用到了線性基的一個性質,線性基中的每兩個數xor都不會等於0,
然後在貪心的對獲取的能量進行求和,最終就是可以得到的最大值。
 

#include<bits/stdc++.h>
#include <iostream>
#include <cmath>
#include <cstdio>
#include <stdlib.h>
#include <ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 5;
ll a[maxn];
struct Point{ll num,val;}point[maxn];
bool operator <(Point a,Point b){return a.val>b.val;}
int Build(ll p)
{
        for(int x=63;x>=0;--x)
        {
            if(p&(ll(1ll<<x)))
            {
                if(!a[x])
                {
                    a[x]=p;
                    break;
                }
                p^=a[x];
            }
        }
        if(p) return 1;
    return 0;
}

int main()
{
    int n;
        cin>>n;
        memset(a,0,sizeof(a));
        for(int i=0;i<n;++i) cin>>point[i].num>>point[i].val;
        sort(point,point+n);
        ll ans=0;
        for(int i=0;i<n;++i)
            if(Build(point[i].num))
                ans+=point[i].val;
        cout<<ans<<endl;
    return 0;
}