bzoj 2460

裸的线性基+贪心...

把权值从大到小排序后逐个将编号插入线性基中,如果这个编号已经能用线性基中的值表示出来了就不插入

为什么这么做是正确的?

线性基定义

我们希望总权值最大,所以当然从大到小排序

然后逐个插入线性基中,如果我们惊喜地发现这个值已经能用线性基中元素表示出来,说明线性基中一定存在一个元素集合,使得这些元素与这个值的异或和为0!

那就不合法了嘛

什么?为什么贪心是对的?

线性基定义

假设如果我们放进去了一个权值大的(设编号为$a$),我们就无法放进去两个权值略小的(设编号为$b,c$),且b,c权值之和大于a的权值

那么根据线性基定义,我们可以用a与其他元素表示出$b,c$,那么我们一定可以用$b$与其他元素表示出$a,c$!(基于异或运算规则,可以立刻得出这一点)

那么自然选b不如选a更优

那么就结束了

#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
struct node
{
    ll num;
    int val;
    friend bool operator < (node a,node b)
    {
        return a.val>b.val;
    }
}w[1005];
int n,ans;
ll p[65];
int get_p(ll x)
{
    for(int i=61;i>=0;i--)
    {
        if(!(x&(1ll<<i)))continue;
        else if(p[i])x^=p[i];
        else {p[i]=x;break;}
    }
    return (x!=0);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%lld%d",&w[i].num,&w[i].val);
    sort(w+1,w+n+1);
    for(int i=1;i<=n;i++)ans+=get_p(w[i].num)*w[i].val;
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-05-06 20:18  lleozhang  Views(158)  Comments(0Edit  收藏  举报
levels of contents