[bzoj2460][BeiJing2011]元素——另类kruskal最大生成树?+线性基 大佬们的博客 Some Links

题目大意:

大概就是给定每一个点,有一个编号和一个权值,求权值最大的点集使得点集中不存在异或和为0的子集。

思路:

为数不多的没看题解做出来的题?
学线性基的时候看到有这一题,看成了求最大异或和,然后就兴冲冲地想把它当成裸题去。然后发现还有一个权值是什么鬼?
我是这么理解的,大概就是一个异或和为0的集合可以看成是一个环,然后整个全集就是一个图中有数不清的环(当然可能是环套环?),然后我们就是要在环上删边使得没有一个环且权值和最大。刚开始还愣住了,想这该怎么做,然后发现这不就是最大生成树吗?
排一遍序之后直接用线性基判断新加进去的边是否构成环即可(就是出现了异或和为0的子集)。
好像有人用拟阵去证明贪心的正确?反正我知道Kruskal是正确的。。。

/*======================================
 * Author : ylsoi
 * Problem : bzoj2460
 * Algorithm : Kruskal&Linear Basis
 * Time : 2018.6.9
 * ====================================*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<climits>
using namespace std;
void File(){
    freopen("bzoj2460.in","r",stdin);
    freopen("bzoj2460.out","w",stdout);
}
template<typename T>bool chkmax(T &_,T __){return _<__ ? (_=__,1) : 0;}
template<typename T>bool chkmin(T &_,T __){return _>__ ? (_=__,1) : 0;}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf INT_MAX
const int maxn=1000+10;
struct node{
    ll num;int va;
    bool operator < (const node & tt) const {
        return va>tt.va;
    }
}a[maxn];
int n;
ll b[70],ans;
bool insert(ll x){
    DREP(i,62,1){
        if(!x)return false;
        ll p=1ll<<(i-1);
        if(!(p&x))continue;
        if(!b[i]){
            b[i]=x;
            break;
        }
        x^=b[i];
        if(!x)return false;
    }
    return true;
}
int main(){
    File();
    scanf("%d",&n);
    REP(i,1,n)scanf("%lld%d",&a[i].num,&a[i].va);
    sort(a+1,a+n+1);
    REP(i,1,n)if(insert(a[i].num))
        ans+=a[i].va;
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/80636696
今日推荐