Ac链接
- 给定n个数,求子集异或和的第k大。\(n\le10^5,a_i\le10^9\)。
- 第一步肯定是构造线性基。设线性基的基底数量为k,那么子集异或和本质不同的个数为\(2^k\)(如果有为0的情况)。其实求第k大很简单,你把k拆分成2进制,对应基底从左到右的每一位,如果为1就异或上去就行了。不过我们需要分为两种情况,一个是存在异或和为0的情况,一个是不存在的。如果不存在异或和为0,需要把k+1。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100;
ll t,n,m,q,cnt,k,ans,a[N];
void insert(ll v){
for(int i=63;i>=0;--i) if((v>>i)&1){
if(a[i]) v^=a[i];
else{
for(int j=i-1;j>=0;--j)
if((v>>j)&1) v^=a[j];
for(int j=i+1;j<=63;++j)
if((a[j]>>i)&1) a[j]^=v;
a[i]=v;
break;
}
}
}
int main(){
scanf("%lld",&t);
for(int cas=1;cas<=t;++cas){
memset(a,0,sizeof(a));
scanf("%lld",&n);ll x;
for(int i=1;i<=n;++i){
scanf("%lld",&x);
insert(x);
}
cnt=0;
for(int i=0;i<=63;++i) if(a[i]) cnt++;
scanf("%lld",&m);
printf("Case #%d:\n",cas);
for(int i=1;i<=m;++i){
scanf("%lld",&k);
if(cnt==n) k++;
ll ans=0;ll tmp=cnt;
if(k>(1LL<<cnt)){printf("-1\n");continue;}
for(int i=63;i>=0;--i){
if(a[i]){
ll now=1LL<<(tmp-1);
if(k>now) k-=now,ans^=a[i];
tmp--;
}
}
printf("%lld\n",ans);
}
}
return 0;
}
原文地址:https://www.cnblogs.com/kgxw0430/p/10425276.html
时间: 2024-10-05 10:04:22