HDU_3949 XOR gauss

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 ;
}

你可能感兴趣的:(HDU_3949 XOR gauss)