题意:给N个数, 求异或和第k大的数
线性基:高斯消元构造对角矩阵,具体理论证明看其他详细介绍
把k二进制拆分,第i位上有1,就把第i个线性基异或进来。
原因:
因为线性基是一堆高位上的1(或许有一些位动不了),然后把这样每一位可以填0/1,跟二进制差不多,第i位为1时取当前行的矩阵值,就能得到第k大的值了
注意:输出lld会wa,输出I64u
#include <iostream>
#include <string.h>
using namespace std;
#define ll unsigned long long
#define M 63
int n;
ll dat[10005],flag,tot;
ll mt[70];
void gauss()
{
memset(mt,0,sizeof(mt));
ll i,j,k,r;
flag=0;
for(i=1;i<=n;i++)
{
for(j=M;~j;j--)
{
if( (dat[i]>>j)&1 )
if( !mt[j] )
{
mt[j]=dat[i];
for(k=0;k<=M;k++)
for(r=k+1;r<=M;r++)
if( (mt[r]>>k)&1 )
mt[r]^=mt[k];
break;
}
else dat[i]^=mt[j];
}
if( dat[i]==0) flag=1;
}
}
int main()
{
int T,t,m;
ll i,q;
scanf("%d",&T);
for(t=1;t<=T;t++)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%I64u",&dat[i]);
gauss();
for(i=0,tot=0;i<=M;i++)
if(mt[i])
mt[tot++]=mt[i];
printf("Case #%d:\n",t);
scanf("%d",&m);
while(m--)
{
scanf("%I64u",&q);
ll ans=0;
q-=flag;
if(q==0)
printf("0\n");
else if( q>>tot )
printf("-1\n");
else
{
for(i=0;i<tot;i++)
{
if((q>>i)&1)
ans^=mt[i];
}
printf("%I64u\n",ans);
}
}
}
return 0;
}