P4869 albus就是要第一个出场

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;
}
原文地址:https://www.cnblogs.com/Wolfycz/p/13690679.html