HDU 3949 XOR (线性基,模板)

Posted 小坏蛋_千千

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 3949 XOR (线性基,模板)相关的知识,希望对你有一定的参考价值。

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

 

题意

给定长度为 n n 的数组,有 q 次查询,每次查询由数组的子集所异或出结果的第 k k 小值是多少。

 

思路

将数组所有元素插入线性基中,然后对其进行 rebuild 操作:从高位往低位开始枚举,对于每一个 i ,枚举 j<i j < i ,假如 d[i] d [ i ] 的第 j j 位是 1 ,则让它异或一次 d[j] d [ j ] (消除当前位)。

操作结束以后,对于 d[i] d [ i ] 来说只有 i i 这一位为 1 ,其余位都为 0 0 ,我们按从小到大的顺序把其中的非零元素放入 p 中。

在查询第 k k 大异或值的时候,我们根据 k 的二进制进行构造,对于 1 1 的位,便异或上相应的 p[i] ,仔细想想这样的构造方法是正确的。


需要注意的是由线性基所异或出的结果都是非零的,而查询的第 k k 小异或值可能为零,于是我们需要在构造线性基的时候判断当前这些数能否异或出 0 ,再对最终所要查询的结果进行特判即可。

 

AC 代码

#include <bits/stdc++.h>
#define IO                       \\
    ios::sync_with_stdio(false); \\
    cin.tie(0);                  \\
    cout.tie(0);
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
int n, q;

class LinearBase 
public:
    const static int maxn = 64 - 1;
    LL d[maxn], p[maxn], tot;
    void clear() 
        tot = 0;
        memset(d, 0, sizeof(d));
        memset(p, 0, sizeof(p));
    

    bool insert(LL val) 
        for (int i = maxn - 1; i >= 0; i--) 
            if ((val >> i) & 1) 
                if (!d[i]) 
                    d[i] = val;
                    break;
                 else 
                    val ^= d[i];
                
            
        
        return val > 0;
    

    LL query_max(LL def = 0) 
        LL res = def;
        for (int i = maxn - 1; i >= 0; i--) 
            res = max(res, res ^ d[i]);
        
        return res;
    

    LL query_min() 
        for (int i = 0; i < maxn; i++) 
            if (d[i])
                return d[i];
        
        return 0;
    

    void rebuild() 
        memset(p, 0, sizeof(p));
        tot = 0;
        for (int i = maxn - 1; i >= 0; i--) 
            for (int j = i - 1; j >= 0; j--) 
                if ((d[i] >> j) & 1) 
                    d[i] ^= d[j];
                
            
        
        for (int i = 0; i < maxn; i++) 
            if (d[i]) 
                p[tot++] = d[i];
            
        
    

    LL query_kth(LL k) 
        if (k >= 1LL << tot) 
            return -1;
        
        LL res = 0;
        for (int i = 0; i < maxn; i++) 
            if ((k >> i) & 1) 
                res ^= p[i];
            
        
        return res;
    

 lb;

int main() 
#ifdef LOCAL_IM0QIANQIAN
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#else
    IO;
#endif // LOCAL_IM0QIANQIAN

    int T;
    cin >> T;
    for (int ti = 1; ti <= T; ti++) 
        bool flag = true;
        lb.clear();
        cin >> n;
        for (int i = 0; i < n; i++) 
            LL x;
            cin >> x;
            flag &= lb.insert(x);
        
        cout << "Case #" << ti << ":" << endl;
        cin >> q;
        lb.rebuild();
        for (int i = 0; i < q; i++) 
            LL x;
            cin >> x;
            cout << lb.query_kth(x - 1 + flag) << endl;
        
    
    return 0;

以上是关于HDU 3949 XOR (线性基,模板)的主要内容,如果未能解决你的问题,请参考以下文章

模板线性基

Nowcoder 练习赛26 D xor序列 ( 线性基 )

P3812 模板线性基

LG3812 「模板」线性基 线性基

[算法模板]线性基

HDU3949:XOR——题解