P4869 albus就是要第一个出场

Description
已知一个长度为\(n\)的正整数序列\(A\)(下标从1开始), 令 \(S = \{ x | 1 \leqslant x \leqslant n \}\), \(S\)的幂集\(2^S\)定义为\(S\)所有子集构成的集合。定义映射$ f : 2^S \to 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]\)

\(1\leqslant N\leqslant 10^5\),其余各数均不超过\(10^9\)


首先求出序列\(A\)的线性基\(V\),如果序列\(B\)不存在重复元素,我们可以用二分找到\(Q\)的排名,如果存在重复元素,可以通过简单打表猜测,每个数都会出现同样的次数,次数为\(2^{N-|V|}\)

证明如下:

记所有未加入线性基的元素集合为\(C\),则\(|C|=N-|V|\),我们选取其任意子集\(S\)

根据线性基的性质可得,\(\forall x\in S\),存在唯一的\(V\)中元素的组合,使得其异或和为\(x\),即\(V\)存在唯一子集,使得其异或和为\(x\)

那么对于\(\forall x\in 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\n");
		return 0;
	}
	int Ans=(K-1)%P*mlt(2,n-tot)%P;
	printf("%d\n",(Ans+1)%P);
	return 0;
}
posted @ 2020-09-18 13:02  Wolfycz  阅读(183)  评论(0编辑  收藏  举报