• BZOJ2844:albus就是要第一个出场——题解


    https://www.lydsy.com/JudgeOnline/problem.php?id=2844

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

    这话真的不是人说出来的。

    简单翻译一下题就是序列所有的子集(可为空)的异或和经过排序,给一个q,求q在排序后序列中的位置下标。

    参考:https://blog.sengxian.com/algorithms/linear-basis

    如果是无重的,我们按照类似HDU3949:XOR的做法二进制分解q即可做(看代码应该更好理解吧)。

    但是有重集合就很尴尬。

    不过我们有对于一个数x,它出现次数一定是2^(n-size)(size为线性基大小)。

    详细证明可以看参考,这里给出我的想法。

    显然对于原线性基有且仅有一种方法构造出来x,且有且仅有一种方法构造出来非线性基内但却在a序列中的数。

    那么对于非线性基内但却在a序列中的数有(n-size)个,它们和线性基内的数异或为0的方法有(n-size),排列组合就有2^(n-size)个,再与仅有一种方法构造出来x,就有2^(n-size)个了。

    于是我知道了它去重前的排名,它排名前面的数都乘上2^(n-size)后+1即为答案。

    PS:自己曾经也纠结过第一次算ans是否需要减一,但后来发现集合可为空……emmm这不值就有0了吗,对于0也满足这个性质啊,但是ans算排名的时候忽略了0啊。所以相当于ans-1+1=ans了啊。

    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<cstring>
    #include<cmath>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    const int N=100010;
    const int p=10086;
    const int BASE=30;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    int qpow(int k,int n){
        int res=1;
        while(n){
        if(n&1)res=res*k%p;
        k=k*k%p;
        n>>=1;
        }
        return res;
    }
    int a[N],b[BASE+4],cnt;
    vector<int>mp;
    int main(){
        int n=read();
        for(int i=1;i<=n;i++){
        a[i]=read();
        for(int j=BASE;j>=0;j--){
            if(a[i]>>j&1){
            if(b[j])a[i]^=b[j];
            else{
                b[j]=a[i];cnt++;
                break;
            }
            }
        }
        }
        int q=read(),ans=0;
        for(int i=0;i<=BASE;i++)
        if(b[i])mp.push_back(i);
        for(int i=0;i<mp.size();i++){
        if(q>>mp[i]&1)ans+=1<<i;
        ans%=p;
        }
        ans=ans*qpow(2,n-cnt)%p+1;
        printf("%d
    ",ans%p);
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    PHP做ERP, CRM, CMS系统需要注意哪些地方
    java封装小实例
    java中数组的数组问题
    switch语句小练习
    java交换两个变量值a,b的多钟方法
    java中 i = i++ 的结果
    每日java基础知识(01)
    计算机存储负数以及int转byte时-128的出现
    python RSA 加密
    CentOS 7 安装 建立svn仓库 远程连接
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8819185.html
Copyright © 2020-2023  润新知