zoukankan      html  css  js  c++  java
  • BZOJ_2844_albus就是要第一个出场_线性基

    BZOJ_2844_albus就是要第一个出场_线性基

    Description

    已知一个长度为n的正整数序列A(下标从1开始), 令 S = { x | 1 <= x <= n }, S 的幂集2^S定义为S 所有子
    集构成的集合。定义映射 f : 2^S -> Zf(空集) = 0f(T) = XOR A[t] , 对于一切t属于T现在albus把2^S中每个集
    合的f值计算出来, 从小到大排成一行, 记为序列B(下标从1开始)。 给定一个数, 那么这个数在序列B中第1
    次出现时的下标是多少呢?

    Input

    第一行一个数n, 为序列A的长度。接下来一行n个数, 为序列A, 用空格隔开。最后一个数Q, 为给定的数.

    Output

    共一行, 一个整数, 为Q在序列B中第一次出现时的下标模10086的值.
     

    Sample Input

    3

    1 2 3

    1

    Sample Output

    3

    样例解释:

    N = 3, A = [1 2 3]

    S = {1, 2, 3}

    2^S = {空, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}}

    f(空) = 0

    f({1}) = 1

    f({2}) = 2

    f({3}) = 3

    f({1, 2}) = 1 xor 2 = 3

    f({1, 3}) = 1 xor 3 = 2

    f({2, 3}) = 2 xor 3 = 1

    f({1, 2, 3}) = 0

    所以

    B = [0, 0, 1, 1, 2, 2, 3, 3]

    HINT

    数据范围:

    1 <= N <= 10,0000

    其他所有输入均不超过10^9


    基本思路是求出有几个小于这个数且本质不同的数。

    如果构成线性基的数有K个,那么每种方案都可以找出$2^{n-K}$个。

    然后我们可以正着求第K大异或和,也可以很巧妙的解决这个数是第几大的异或和。

    由于这$2^{K}$个异或和与他们的排名是一一对应的,我们可以这样做。

    把线性基中所有第一位的1抠出来,假设现在有个数x,将x拆成二进制的形式,在线性基中的第i位是1就相当于有1<<i个比他小的,需要加上。

    其实就是反过来做,求反过来的第K大异或和,只不过此时的线性基是第i个向量恰好在第i位为1。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int mod=10086;
    int qp(int x,int y) {
        int re=1; for(;y;y>>=1,x=x*x%mod) if(y&1) re=re*x%mod; return re;
    }
    int n,b[40],a[40];
    void insert(int x) {
        int i;
        for(i=30;i>=0;i--) {
            if(x&(1<<i)) {
                if(b[i]) x^=b[i];
                else {
                    b[i]=x; return ;
                }
            }
        }
    }
    void Guass() {
        int i,j;
        for(i=30;i>=0;i--) {
            if(b[i]) {
                for(j=30;j>=0;j--) {
                    if(i!=j&&(b[j]&(1<<j))) b[j]^=b[i];
                }
            }
        }
    }
    int main() {
        scanf("%d",&n);
        int i,x;
        for(i=1;i<=n;i++) scanf("%d",&x),insert(x);
        Guass();
        int Q;
        scanf("%d",&Q);
        int k=0;
        for(i=0;i<=30;i++) if(b[i]) a[++k]=i;
        int re=0;
        for(i=1;i<=k;i++) {
            if(Q&(1<<(a[i]))) {
                re=(re+(1<<(i-1)))%mod;
            }
        }
        printf("%d
    ",(re*qp(2,n-k)%mod+1)%mod);
    }
    

      

  • 相关阅读:
    OpenJDK源码研究笔记(十二):JDBC中的元数据,数据库元数据(DatabaseMetaData),参数元数据(ParameterMetaData),结果集元数据(ResultSetMetaDa
    Java实现 LeetCode 257 二叉树的所有路径
    Java实现 LeetCode 257 二叉树的所有路径
    Java实现 LeetCode 257 二叉树的所有路径
    Java实现 LeetCode 242 有效的字母异位词
    Java实现 LeetCode 242 有效的字母异位词
    Java实现 LeetCode 242 有效的字母异位词
    Java实现 LeetCode 241 为运算表达式设计优先级
    Java实现 LeetCode 241 为运算表达式设计优先级
    Java实现 LeetCode 241 为运算表达式设计优先级
  • 原文地址:https://www.cnblogs.com/suika/p/9187006.html
Copyright © 2011-2022 走看看