hdu3949

XOR

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1841    Accepted Submission(s): 586


Problem Description
XOR is a kind of bit operator, we define that as follow: for two binary base number A and B, let C=A XOR B, then for each bit of C, we can get its value by check the digit of corresponding position in A and B. And for each digit, 1 XOR 1 = 0, 1 XOR 0 = 1, 0 XOR 1 = 1, 0 XOR 0 = 0. And we simply write this operator as ^, like 3 ^ 1 = 2,4 ^ 3 = 7. XOR is an amazing operator and this is a question about XOR. We can choose several numbers and do XOR operatorion to them one by one, then we get another number. For example, if we choose 2,3 and 4, we can get 2^3^4=5. Now, you are given N numbers, and you can choose some of them(even a single number) to do XOR on them, and you can get many different numbers. Now I want you tell me which number is the K-th smallest number among them.
 

Input
First line of the input is a single integer T(T<=30), indicates there are T test cases.
For each test case, the first line is an integer N(1<=N<=10000), the number of numbers below. The second line contains N integers (each number is between 1 and 10^18). The third line is a number Q(1<=Q<=10000), the number of queries. The fourth line contains Q numbers(each number is between 1 and 10^18) K1,K2,......KQ.
 

Output
For each test case,first output Case #C: in a single line,C means the number of the test case which is from 1 to T. Then for each query, you should output a single line contains the Ki-th smallest number in them, if there are less than Ki different numbers, output -1.
 

Sample Input
 
  
2 2 1 2 4 1 2 3 4 3 1 2 3 5 1 2 3 4 5
 

Sample Output
 
  
Case #1: 1 2 3 -1 Case #2: 0 1 2 3 -1
Hint
If you choose a single number, the result you get is the number you choose. Using long long instead of int because of the result may exceed 2^31-1.

题意:从n个数中任选m(m>=1)个数异或起来,求所有可能的异或和的第k小值。

这题传说是什么线性基之类的,但实际并不完全是基,因为基的概念是两两内积为0.

下面说题解:

简单来说,我有a和b两个数,假设(a,b)是a和b能够异或出来的所有值,当然这里(a,b)={a,b,a^b},可能要去重,其实我们不用关注具体是多少,只要知道用(a,b)表示就行了,那么我们有结论(a,b)=(a^b,b)=(a^b,a)=(a,b,a^b)等等,同时还有交换律(a,b)=(b,a),我整一个简单的吧(a,b)=(a^b,b),证明两个集合相等,显然是证互相包含了,首先a和b可以变出a^b,这样我们就可以利用a^b和b来生成其他数,于是(a,b)是包含(a^b,b)的,同理a^b和b可以先变出a^b^b=a,于是(a^b,b)包含(a,b),因此有(a,b)=(a^b,b),其他同理可证.

这里做推广到(a1,a2,a3,....,an),比如b1=a1^a2,那么保留至少一个a1或a2,我们有(b1,a2,a3,...,an)=(a1,a2,a3,...,an),以此我们可以一直做下去...甚至完全变成(b1,b2,b3,...,bn).这是个什么过程呢?很明显高斯消元吗.

既然(a1,a2,a3,...,an)=(b1,b2,b3,...,bn),那么我们想方设法让b1,b2,b3,...,bn尽量变成基,也就是理想情况下两两内积为0.我们考虑将a1,...,an写成二进制形式,而异或等价于模2加法。

于是a1,..,an所能表示的所有数的形式为c=(a1*x1)^(a2*x2)^....^(an*xn),x1,x2,...xn取{0,1},xi表示ai这个数取不取,我们按位考虑,因为所有ai最多60位,因此c[i]=(a1[i]*x1+a2[i]*x2+...+an[i]*xn)%2; c[i]表示c的二进制表示第i位,ak[i]同理.

这样我们也成矩阵形式

(a1[0],a2[0],...,an[0])       (x[1])            (c[0])

(a1[1],a2[1],...,an[1])       (x[2])            (c[1])

(................................)      (*****)   %2= (*****)

(.....................................) (*****)            (*****)

(a1[60],a2[60],...,an[60]) (x[n])           (c[60])

实际并不是这么做的,我们要将矩阵转置过来

(a1[0],a1[1],...,a1[60])                                    (a1[0])             (a2[0])            (an[0]) (%2)       (c[0])

(a2[0],a2[1],...,a2[60])                                    (a1[1])             (a2[1])            (an[1]) (%2)       (c[1])

(.................................) 然后写成这种形式x1 (........)   +  x2  (........)   + xn  (........) (......)   =  (......)

(.................................)                                     (........)             (.........)            (........) (......)       (......)

(an[0],an[1],...,an[60])                                    (a1[60])          (a2[60])          (an[60]) (%2)      (c[n])


这样基的形式就很明显,于是我们对转置矩阵进行高斯消元,理想情况是消成对角型矩阵。

(1,0,0,0,0)

(0,1,0,0,0)

(0,0,1,0,0)

(0,0,0,1,0)

(0,0,0,0,1)

这样是真正的两两内积为0,这样当所有xi遍历{0,1},将得到2^n-1种结果,-1是因为所有xi不能同时取0,因为题目条件限制,必须取m(m>=1)个数异或.

不理想情况呢?

(1,0,0,0,0)

(0,1,0,0,1)

(0,0,1,0,0)

(0,0,0,1,1)

列数多的情况

(1,0,1,0,0)

(0,1,1,0,1)

(0,0,0,1,1)

(0,0,0,0,0)

消不成对角型的情况

这些列可能会有多个1,但是实际并不影响

比如我们看这个矩阵

(1,0,1,0,0)

(0,1,1,0,1)

(0,0,0,1,1)

(0,0,0,0,0)

我们看前两列(从左到右是高位->低位),可以组成(11),(10),(01),(00),第1位为1对应了x1=1,第2位1对应了x2=1,

他们之所以可以取遍2^2=4种可能,是因为他们是基,基是独立的,那么第3位呢?对角上没有1啊,这样其实第3位的值是取决于前2位的,也就是固定的,比如(11)第三位必然是0,因为(1,1)代表x1=x2=1,也就是第1,2行都是取的,由于第1,2行的第3列都是1,因此异或起来为0(这个取决于奇偶性了),于是第3位是确定的,因此可以得到(110),(101),(011),(000),由于第4位又是对角上的1(位置并不一定在对角线,但1所在的行这个1是第一次出现,其实就是一个行阶梯型),显然又是独立的,也就是x3可取0和1

x3=1,得到(1101),(1011),(0111),(0001)

x3=0,得到(1100),(1010),(0110),(0000)

可以发现每遇到对角上一个1,能表示的数就翻倍了。

看第5列,由于是多出来的,对角没有元素了,同样的第5位是前4位决定的,如(1101)表示x1=x2=x3=1,那么第5位就是第2,3行第5列的1异或起来,也就是(11010)。

说了一堆,也就是所能表示的数的个数就是pow(2,行阶梯型的对角1的个数),注意0的问题,如果不能取0,则需-1,能不能取0,取决于最后一行是不是全0,若是的话,则取x1=x2=...=xn-1=0,xn=1,就能得到0,否则得不到0.

说了一堆,看出了类似线性基的样子,并且可以发现从第1列到最后一列的扫描过程,生成的数字是排好序的,恰好可以发现第k大,如果能取0,则k=k-1,那么k的二进制表示刚好对应了线性基的取法,例如k=(1101),则表示取x1=x2=x4=1,x3=0这个对照上面的扫描过程理解一下吧,不详细解释了,也比较难解释清楚!

提交一直WA,各种调试对拍,最后发现一个神奇的BUG,见代码。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#define Maxn 10010
#define ll long long
using namespace std;

ll a[Maxn];
int d;
void gauss(int n){
    int r=1,i,j;
    for(i=60;i>=0;i--){
        if(!(1LL<<i&a[r])){
            for(j=r+1;j<=n;j++)
                if(1LL<<i&a[j]) break;
            if(j>n) continue;
            swap(a[r],a[j]);
        }
        for(j=1;j<=n;j++){
            if(j==r||!(1LL<<i&a[j])) continue;
            a[j]^=a[r];
        }
        r++;
        if(r==n+1) break; //BUG:r=n+1会利用前一组数据,需要break
    }
    d=r-1;
}
ll query(ll x,int n){
    x-=d!=n;
    if(!x) return 0;
    if(x>=(1LL<<d)) return -1;
    ll ans=0;
    for(int i=d-1;i>=0;i--)
        if(x>>i&1) ans^=a[d-i];
    return ans;
}
int main()
{
    int t,n,m,cas=1;
    ll x;
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=1;i<=n;i++)
            scanf("%I64d",a+i);
        gauss(n);
        cin>>m;
        printf("Case #%d:\n",cas++);
        while(m--){
            scanf("%I64d",&x);
            printf("%I64d\n",query(x,n));
        }
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/u012866104/article/details/50126361