版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sxy201658506207/article/details/84667672
从n个数中任选m(m>=1)个数异或起来,求所有可能的异或和的第k小值。
用到了0能不能被异或出来的问题。如果线性基的大小和原数组一样,0是不能被异或出来的,否则可以。
在求k小值的时候要注意
#include<bits/stdc++.h>
#include <iostream>
#include <cmath>
#include <cstdio>
#include <stdlib.h>
#include <ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int maxn = 1e6 + 5;
using namespace std;
ll a[10005],m;
ll p[10005];
bool flag;
int cnt=0;
void init()
{
memset(a,0,sizeof(a));
memset(p,0,sizeof(p));
cnt=0;
flag=false;
}
void build(ll p)
{
for(int x=62;x>=0;--x)
{
if(p&ll(1ll<<x))
{
if(a[x]==0)
{
a[x]=p;
break;
}
p^=a[x];
}
}
if(p==0) flag=true;
}
void rebuild()
{
for(int i=62;i>=0;--i)
{
if(a[i]==0)continue;//
for(int j=i-1;j>=0;--j)
{
if(a[j]==0)continue;
if(a[i]&ll(ll(1<<j)))
a[i]^=a[j];
}
}
for(int i=0;i<=62;++i)
if(a[i])
p[cnt++]=a[i];
}
ll query_Kth(ll k)
{
ll ret=0;
if(flag) k--;
if(k==0) return 0;
if(k>=ll(1LL<<cnt))return -1;
for(int i=62;i>=0;--i)
if(k&ll(1ll<<i))ret^=p[i];
return ret;
}
int main()
{
int T,n;
cin>>T;
for(int ca=1;ca<=T;ca++)
{
init();
printf("Case #%d:\n",ca);
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>m;
build(m);
}
rebuild();
int t;
cin>>t;
while(t--)
{
ll x;
cin>>x;
printf("%lld\n",query_Kth(x));
}
}
return 0;
}