Description
已知一个长度为(n)的正整数序列(A)(下标从1开始), 令 (S = { x | 1 leqslant x leqslant n }), (S)的幂集(2^S)定义为(S)所有子集构成的集合。定义映射$ f : 2^S o Z,f(emptyset) = 0,f(T) = mathrm{XOR}{A_t}, (t in 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
HINT
记(otimes)为xor运算
(N = 3, A = [1,2,3])
(S = {1, 2, 3})
(2^S = {emptyset, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}})
(f(emptyset) = 0)
(f({1}) = 1)
(f({2}) = 2)
(f({3}) = 3)
(f({1, 2}) = 1 otimes 2 = 3)
(f({1, 3}) = 1 otimes 3 = 2)
(f({2, 3}) = 2 otimes 3 = 1)
(f({1, 2, 3}) = 1 otimes 2 otimes 3 = 0)
所以 (B=[0,0,1,1,2,2,3,3])
(1leqslant Nleqslant 10^5),其余各数均不超过(10^9)
首先求出序列(A)的线性基(V),如果序列(B)不存在重复元素,我们可以用二分找到(Q)的排名,如果存在重复元素,可以通过简单打表猜测,每个数都会出现同样的次数,次数为(2^{N-|V|})
证明如下:
记所有未加入线性基的元素集合为(C),则(|C|=N-|V|),我们选取其任意子集(S)
根据线性基的性质可得,(forall xin S),存在唯一的(V)中元素的组合,使得其异或和为(x),即(V)存在唯一子集,使得其异或和为(x)
那么对于(forall xin B),我们都可以找到(2^{|C|})种方案,证毕
然后记得特判一下0的位置就好
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>inline T frd(T x){
int f=1; char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
template<typename T>inline T read(T x){
int f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
template<typename T>inline T min(T x,T y){return x<y?x:y;}
template<typename T>inline T max(T x,T y){return x>y?x:y;}
template<typename T>inline T swap(T &x,T &y){T t=x; x=y,y=t;}
const int N=30,P=10086;
int A[N+10],tot;
int Add(int x){
for (int i=N;~i;i--){
if (x&(1<<i)){
if (A[i]) x^=A[i];
else{
A[i]=x;
return 1;
}
}
}
return 0;
}
int Find(int K){
int Ans=0;
for (int i=0;i<=N;i++){
if (A[i]){
if (K&1) Ans^=A[i];
K>>=1;
}
}
return Ans;
}
int Binary_search(int x){
int l=1,r=(1<<tot)-1;
while (l<r){
int mid=(l+r)>>1;
Find(mid)>=x?r=mid:l=mid+1;
}
return l+1;
}
int mlt(int a,int b){
int Ans=1;
for (;b;b>>=1,a=a*a%P) if (b&1) Ans=Ans*a%P;
return Ans;
}
int main(){
int n=read(0);
for (int i=1;i<=n;i++) tot+=Add(read(0));
for (int i=N;~i;i--)
for (int j=i;j;j--)
if (A[i]&(1<<(j-1)))
A[i]^=A[j-1];
int x=read(0),K=Binary_search(x);
if (!x){
printf("1
");
return 0;
}
int Ans=(K-1)%P*mlt(2,n-tot)%P;
printf("%d
",(Ans+1)%P);
return 0;
}