BZOJ 2844 albus就是要第一个出场(线性基)

来源:互联网 发布:mac音频驱动异常 编辑:程序博客网 时间:2024/05/23 01:33

Description

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

Input

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

(1n105,Ai109)

Output

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

Sample Input

3

1 2 3

1

Sample Output

3

Solution

从这n个数选出子集异或得到的数集与其线性基选出子集异或得到的数集相同(均记为C ),设其线性基大小为m,则集合C的大小为2m ,则对于集合C中任一数x, 从剩下的nm个数中选取子集异或得到2nm个数,从中取一个数y ,那么必然可以从线性基中选出若干数异或得到x^y,故集合C中每个数都会在序列B中出现2nm次,那么为了求Q这个数在序列B中的位置,只需要求在集合C中有多少数小于Q即可

对于m个线性基异或出的2m个数,考虑m个线性基二进制表示的最高位,这些最高位显然两两不同,把这些最高位从高到低看作m个位即可得到QC集合中的位置

Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<map>#include<set>#include<ctime>using namespace std;typedef long long ll;typedef pair<int,int>P;const int INF=0x3f3f3f3f,maxn=100005;#define mod 10086int n,a[maxn],base[33];int Pow(int a,int b){    int ans=1;    while(b)    {        if(b&1)ans=ans*a%mod;        a=a*a%mod;        b>>=1;    }    return ans;}int main(){    while(~scanf("%d",&n))    {        for(int i=1;i<=n;i++)scanf("%d",&a[i]);        memset(base,0,sizeof(base));        for(int i=1;i<=n;i++)            for(int j=29;j>=0;j--)                if((a[i]>>j)&1)                {                    if(!base[j])                    {                        base[j]=a[i];                        break;                    }                    else a[i]^=base[j];                }        int m=0;        for(int i=0;i<=29;i++)            if(base[i])base[m++]=i;        int q,x=0;        scanf("%d",&q);        for(int i=0;i<m;i++)            if((q>>base[i])&1)                x^=1<<i;        x%=mod;        printf("%d\n",(x*Pow(2,n-m)+1)%mod);    }    return 0;}
阅读全文
0 0
原创粉丝点击