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); }
Copyright:http://www.cnblogs.com/candy99/