题意: 给N个数,从中至少选取1个数的异或值,问第K小的是多少?
用高斯消元法搞基。将N个数化为二进制,求出非线性相关的基。
因为要求最小,则从高位开始消去。
#include<stdio.h>
#include<string.h>
#include<math.h>
#define LL long long
#define M 63
#define maxN 100000
#include<algorithm>
using namespace std;
int N;
LL a[maxN+10];
LL d[65];
int tot;
int ok;
void guass()
{
int j=1;
for (int i=M-1;i>=0;i--)
{
int k;
for (k=j;k<=N;k++)
if ((a[k]>>i)&1)
break;
if (k==N+1)
continue;
swap(a[k],a[j]);
for (k=1;k<=N;k++)
{
if (k!=j && (a[k]>>i)&1)
a[k] ^= a[j];
}
j++;
}
tot = j-1;
if (j==N+1)
ok = 0;
else
ok = 1;
// for (int i=1;i<=tot;i++)
// printf("%I64d ",a[i]);
// printf("\n");
return ;
}
void solve()
{
int Q;
scanf("%d",&Q);
while (Q--)
{
LL n;
scanf("%I64d",&n);
if (ok)
n--;
if (n>=d[tot+1])
{
printf("-1\n");
continue;
}
LL rr = 0;
for (int i=tot;i>=1;i--)
{
if (n&1)
rr ^= a[i];
n >>= 1;
}
printf("%I64d\n",rr);
}
return ;
}
int main()
{
d[1]=1;
for (int i=2;i<=63;i++)
d[i]=d[i-1]*2;
int cas,cast= 0;
scanf("%d",&cas);
while (cas--)
{
scanf("%d",&N);
for (int i=1;i<=N;i++)
scanf("%I64d",&a[i]);
printf("Case #%d:\n",++cast);
guass();
solve();
}
return 0;
}