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; }