正题
题目链接:https://www.luogu.com.cn/problem/P4570
题目大意
给出nnn个物品有aia_iai和bib_ibi。要求选出一个bib_ibi和最大的子集满足其中的aia_iai不能由其中的其他aia_iai异或得到
解题思路
我们发现对于一个集合能否加入一个物品其实就是判断aia_iai是否能插入当前集合的线性基。每次插入一个物品必定会使得一个did_idi改变,也就是每次禁止掉一个did_idi就必定会使得一个物品无法选择。
对于一个无法插入的物品xxx,也就是若干个did_idi异或得到xxx。如果删除其中一个d?d_?d?就可以插入xxx,那么就有若干的did_idi异或xxx得到d?d_?d?也就是我们每次插入一个无法插入的数就可以删除其中的一个数并且不会改变当前的线性基。
那么我们按照bib_ibi从大到小排序然后依次插入,那么无法插入的一定不会插入,因为插入就会替换出一个bib_ibi更大的物品。
时间复杂度O(60n+nlogn)O(60n+n\log n)O(60n+nlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1100;
ll n,a[N],b[N],p[N],d[80],ans;
bool cmp(ll x,ll y)
{return b[x]>b[y];}
void add(ll x,ll y){for(ll i=60;i>=0;i--)if((x>>i)&1ll){if(d[i])x^=d[i];else{d[i]=x;if(x)ans+=y;break;}}return;
}
int main()
{scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld%lld",&a[i],&b[i]),p[i]=i;sort(p+1,p+1+n,cmp);for(ll i=1;i<=n;i++)add(a[p[i]],b[p[i]]);printf("%lld",ans);
}