http://acm.hdu.edu.cn/showproblem.php?pid=3949
题意:
给你N个数,要你从中取出若干个进行异或运算,求最后所有可以得到的异或结果中的
第k小的异或值。N<=10^18
思路:
首先以位数为行,N和数为列,建一个矩阵,然后就对矩阵进行高斯消元,消元之后这
N个数异或的结果就可以用一组线性基来表示了,该线性基的下标编号就是异或值的大
小标号,因此本题就可以得出解了。
代码;
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef unsigned __int64 LL ;
int N ,Q ;
const int NN = 10000 + 10 ;
const int MM = 63 ;
LL a[NN] ;
int ans[MM] , f[MM] ,SS , tot ;
bool ok ;
LL d[MM] ;
void gauss(){
int row, col ,i , j , k;
j = 0 ;
for(row=MM-1;row>=0;row--){
for(k=j;k<N;k++){
if( (a[k]>>row)&1 ) break ;
}
if( k == N ) continue ;
swap( a[k] , a[j] ) ;
for(int i=0;i<N;i++){
if( i!=j && (( a[i]>>row)&1 ) ){
a[i] ^= a[j] ;
}
}
j++ ;
}
tot = j ;
if(j == N) ok = 0 ;
else ok = 1 ;
}
void solve(){
LL aa ;
scanf("%d",&Q);
for(int i=0;i<Q;i++){
scanf("%I64u",&aa);
if( ok ) aa-- ;
if( aa >= d[tot] ){
printf("-1\n"); continue ;
}
LL rr = 0 ;
for(int i=tot-1;i>=0;i--){
if(aa&1) rr ^= a[i] ;
aa >>= 1 ;
}
printf("%I64u\n" , rr );
}
}
int main(){
d[0] = 1 ;
for(int i=1;i<MM;i++) d[i] = d[i-1] * 2 ;
int ccas, cas ;
for(scanf("%d",&ccas), cas=1;cas<=ccas;cas++){
scanf("%d",&N);
for(int i=0;i<N;i++) scanf("%I64u",&a[i]);
gauss() ;
printf("Case #%d:\n",cas) ;
solve() ;
}
return 0 ;
}