BZOJ 2844: albus就是要第一个出场 [高斯消元XOR 线性基]

 

2844: albus就是要第一个出场


 

题意:给定一个n个数的集合S和一个数x,求x在S的$2^n$个子集从小到大的异或和序列中最早出现的位置


 

一开始看错题了...人家要求的是x第一次出现位置不是第x个是谁

求出线性基后我们知道一共有$2^r$个不同的数,再知道每个数出现了几次就好啦

每个数出现了$2^{n-r}$次....因为有$n-r$个线性相关(高斯消元后全0了)的方程异或不影响....

然后就简单了,从高到低枚举二进制位,异或这一位后小于k就加上

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bitset>
using namespace std;
typedef long long ll;
const int N=1e5+5,INF=1e9,P=10086;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int n,x;
int a[N],bin[70];
void ini(){
    bin[0]=1;for(int i=1;i<=30;i++) bin[i]=bin[i-1]<<1;
}    
int now;
void Gauss(){
    now=1;
    for(int i=30;i>=0;i--){
        int j=now;
        while(j<=n&&!(a[j]&bin[i])) j++;
        if(j==n+1) continue;
        if(j!=now) swap(a[j],a[now]);
        for(int k=1;k<=n;k++) 
            if(k!=now&&(a[k]&bin[i])) a[k]^=a[now];
        now++;
    }
    now--;
}
int main(){
    freopen("in","r",stdin);
    ini();
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    Gauss();
    x=read();
    int val=0,sum=0;
    for(int i=1;i<=now;i++) if((val^a[i])<=x){
        val^=a[i];
        sum=(sum+(1<<(now-i))%P)%P;
    }
    for(int i=1;i<=n-now;i++) sum=(sum<<1)%P;
    printf("%d",(sum+1)%P);
}

 

posted @ 2017-02-19 11:53  Candy?  阅读(457)  评论(0编辑  收藏  举报