zoukankan      html  css  js  c++  java
  • hdu 3949 第k大异或组合

    题意:

    给你一些数,其中任选一些数(大于等于一个),那么他们有一个异或和。

    求所有这样的异或和的第k小。

    我们可以将每一位看成一维,然后就是给我们n个60维的向量,求它们线性组合后得到的向量空间中,第k小的向量。

    因为给我们的向量不一定是非线性相关的(即存在一些向量可以被其他向量线性表示出),所以我们先进行异或高斯消元,将这n个数”精简出“一组基底,即精简前得到的向量空间和精简后的到的是一样的。(精简后最多有60个向量)。

    假如我们的到了m个基底,因为它们线性不相关,所以我们有2^m种可能(包括0)。

    高斯消元以后,我们得到的每个数的最高位非零位一定不为相同,我们按照从高位到低位的顺序排序(高斯消元后本来就是这个顺序),并且从上到下,遍历每一个数,并且用他将它上面的数的它的最高位去掉(如果本来就是0就不用),这样就可以证明”能加则加“了。

    然后就二分啦。。。。。

     1 #include <cstdio>
     2 #include <iostream>
     3 #define N 10010
     4 using namespace std;
     5 
     6 typedef long long dnt;
     7 
     8 int n, m, q;
     9 dnt aa[N];
    10 int bit[N];
    11 bool flag;
    12 
    13 void gauss() {
    14     int i=0;
    15     for( int b=60; b>=0 && i<n; b-- ) {
    16         for( int j=i; j<n; j++ ) {
    17             if( (aa[j]>>b)&1 ) {
    18                 swap( aa[i], aa[j] );
    19                 break;
    20             }
    21         }
    22         if( (aa[i]>>b)&1 ) {
    23             bit[i] = b;
    24             for( int j=i+1; j<n; j++ )
    25                 if( (aa[j]>>b)&1 ) aa[j] ^= aa[i];
    26             i++;
    27         }
    28     }
    29     m = i;
    30     for( i=0; i<m; i++ ) {
    31         for( int j=i-1; j>=0; j-- ) {
    32             if( (aa[j]>>bit[i])&1 )
    33                 aa[j] ^= aa[i];
    34         }
    35     }
    36     flag = m<n;
    37 }
    38 dnt query( dnt k ) {
    39     if( !flag ) k++;
    40     if( k>(1LL<<m) ) return -1;
    41     dnt cur = 0;
    42     for( int i=0; i<m; i++ ) {
    43         if( k>(1LL<<(m-1-i)) ) {
    44             k-=(1LL<<(m-1-i));
    45             cur ^= aa[i];
    46         }
    47     }
    48     return cur;
    49 }
    50 int main() {
    51     int T;
    52     scanf( "%d", &T );
    53     for( int cas=1; cas<=T; cas++ ) {
    54         scanf( "%d", &n );
    55         for( int i=0; i<n; i++ )
    56             scanf( "%lld", aa+i );
    57         gauss();
    58         scanf( "%d", &q );
    59         printf( "Case #%d:
    ", cas );
    60         for( int i=0; i<q; i++ ) {
    61             dnt k;
    62             scanf( "%lld", &k );
    63             printf( "%lld
    ", query(k) );
    64         }
    65     }
    66 }
    View Code
  • 相关阅读:
    C语言程序设计I—第四周教学
    C语言程序设计I—第三周教学
    C语言程序设计I—第一周教学
    软工实践(四)——热词统计
    软工实践(三)——结对第一次作业(原型设计)
    软工实践(二)——构建之法读后感
    软工实践(一)——目标和规划
    庄子修身养性哲学
    $Matrix-Tree$定理-题目
    $Matrix-Tree$定理-理论
  • 原文地址:https://www.cnblogs.com/idy002/p/4524711.html
Copyright © 2011-2022 走看看