• hdu 3949 XOR 线性基 第k小异或和


    题目链接

    题意

    给定(n)个数,对其每一个子集计算异或和,求第(k)小的异或和。

    思路

    先求得线性基。

    同上题,转化为求其线性基的子集的第k小异或和

    结论

    (n)个数的线性基为向量组(B={b_0,b_1,b_2,...,b_t}(有b_i[p_i]=1,p_1lt p_2lt ...lt p_t)),记(k)的二进制表示为向量(vec{K}).

    则第(k)小异或和为$$oplus_{vec{K}[i]=1}b_i$$

    (k)的二进制表示中为(1)的那些位所对应的线性基中的向量异或起来的值。

    正确性证明

    对于任意的(1leq ilt jleq tot(tot)为子集的总个数,也即异或和的总个数)

    (i)的二进制表示为(vec{I})(j)的二进制表示为(vec{J}),设从高到低的(vec{I})(vec{J})第一个不同的位为第(pos)位,因为(ilt j),故有(vec{I}[pos]=0, vec{J}[pos]=1).

    记第(i)小异或值为(ii),第(j)小异或值为(jj),对应的向量分别为(vec{II}, vec{JJ}). 根据上述构造第(k)小值的方法,构造(vec{II})时没有异或(b_{pos}),而构造(vec{JJ})时异或了(b_{pos}). 又由线性基的性质,只有(b_{pos}[p_{pos}]=1),故有(vec{II}[p_{pos}]=0, vec{JJ}[p_{pos}]=1).

    (vec{II})(vec{JJ})高位都相同,第(p_{pos})(vec{JJ})大,故(vec{II}lt vec{JJ}),即(iilt jj).

    所以(ilt j ightarrow iilt jj),所以(rank(i)=rank(ii)),得到了一一对应的关系,故构造的正确性得证。

    注意点

    如果原(n)个数表示成的(01)线性相关,那么除了可以用线性基线性组合而得的(2^r-1)个数外,另有最小的异或和为(0).

    Code

    #include <bits/stdc++.h>
    #define maxl 60
    #define LL long long
    using namespace std;
    struct LinearBasis {
        LL a[maxl+1]; bool rel; int sz;
        vector<LL> v;
        LinearBasis() { memset(a, 0, sizeof a); rel = false; sz = 0; v.clear();}
        void insert(LL t) {
            for (int i = maxl; i >= 0; --i) {
                if (!(t >> i & 1)) continue;
                if (a[i]) t ^= a[i];
                else {
                    for (int j = 0; j < i; ++j) if (t >> j & 1) t ^= a[j];
                    for (int j = i+1; j <= maxl; ++j) if (a[j] >> i & 1) a[j] ^= t;
                    a[i] = t, ++sz;
                    return;
                }
            }
            rel = true;
        }
        void basis() {
            for (int i = 0; i <= maxl; ++i) if (a[i]) v.push_back(a[i]);
        }
        LL kth(LL x) {
            LL ret = 0;
            for (int i = 0; i < v.size(); ++i) if (x >> i & 1) ret ^= v[i];
            return ret;
        }
    };
    int kas;
    void work() {
        int n, q; LL x;
        scanf("%d", &n);
        LinearBasis lb;
        for (int i = 0; i < n; ++i) {
            scanf("%lld", &x);
            lb.insert(x);
        }
        lb.basis();
    
        scanf("%d", &q);
        printf("Case #%d:
    ", ++kas);
    
        LL tot = (1LL << lb.sz) - 1;
        for (int i = 0; i < q; ++i) {
            scanf("%lld", &x);
            if (lb.rel) --x;
            if (x > tot) puts("-1");
            else printf("%lld
    ", lb.kth(x));
        }
    }
    int main() {
        int T;
        scanf("%d", &T);
        while (T--) work();
        return 0;
    }
    
    
  • 相关阅读:
    FocusScope学习三: 对FocusScope 的探究与总结
    FocusScope学习二: 很好的理解FocusScope的工作原理
    不同XML之间节点的拷贝
    计算几何DotVector
    计算几何Graham法凸包
    计算几何UVa10652
    线性筛三合一,强大O(n)
    计算几何AngRadVector
    线性筛euler,强大O(n)
    矩阵bzoj1898
  • 原文地址:https://www.cnblogs.com/kkkkahlua/p/7800932.html
Copyright © 2020-2023  润新知