链接: http://acm.hdu.edu.cn/showproblem.php?pid=3949
题意:
给出n个数,从中任意取几个数字异或,求第k小的异或和
思路:
线性基求第k小异或和,因为题目中可以出现异或和为0的情况,但线性基里是不会出现异或和为0的情况,所以我们需要多处理下,将数字全插入到线性基中,如果无法插入也就代表会出现异或和为0的情况,那么求第k小就应该变成求线性基中第k-1小。
实现代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int M = 1e6+;
struct Linear_Basis{
ll b[],nb[],tot;
bool flag = ;
void init(){
flag = ; tot = ;
memset(b,-,sizeof(b));
memset(nb,,sizeof(nb));
} void Insert(ll x){
for(int i = ;i >= ;i --){
if(x&(1LL<<i)){
if(b[i] == -){
b[i] = x;
return ;
}
x ^= b[i];
}
}
flag = ;
return ;
} ll Max(ll x){
ll ret = x;
for(int i = ;i >= ;i --)
ret = max(ret,ret^b[i]);
return ret;
} ll Min(ll x){
ll ret = x;
for(int i = ;i <= ;i ++)
if(b[i]) ret ^= b[i];
return ret;
} void rebuild(){
for(int i = ;i >= ;i --){
if(b[i] == -) continue;
for(int j = i-;j >= ;j --){
if(b[j] == -) continue;
if(b[i]&(1LL<<j)) b[i]^=b[j];
}
}
for(int i = ;i <= ;i ++)
if(b[i]!=-) nb[tot++] = b[i];
} ll K_Min(ll k){
ll res = ;
if(flag == ) k --;
if(k == ) return ;
if(k >= (1LL<<tot))
return -;
for(int i = ;i >= ;i --)
if(k&(1LL<<i))
res ^= nb[i];
return res;
}
}LB; int main()
{
int cas = ,t,n,m;
cin>>t;
while(t--){
LB.init();
cin>>n;
ll x;
for(int i = ;i <= n;i ++){
cin>>x;
LB.Insert(x);
}
LB.rebuild();
printf("Case #%d:\n",cas++);
scanf("%d",&m);
while(m--){
ll k;
scanf("%lld",&k);
printf("%lld\n",LB.K_Min(k));
}
}
return ;
}