[BZOJ2844]albus就是要第一个出场
题目
题解
对于这道题,我们有一个十分强大的结论,先给出这个结论,再给出一个比较感性的证明。
假设我们有一个集合 \(A\),其中 \(|A|=n\),而 \(A\) 的线性基我们记作 \(G\),且 \(|G|=k\),那么对于 \(A\) 所有子集 \(S_i(1\le i\le 2^n)\) 的异或和只会有 \(2^{k}\) 个值,每个值出现的次数为 \(2^{n-k}\) 次。
怎么证明这个结论呢?
我们可以考虑,子集 \(S_i\) 一共有 \(2^n\) 的异或和,但是由 \(G\) 最多可以得出 \(2^k\) 个不同的值,而由线性基的特性,由 \(G\) 得出的值和由 \(A\) 得出的值都是一样的,线性基即原集合的压缩,但是我们实际上可以得到 \(2^n\) 个值,那么 \(2^k\) 和 \(2^n\) 这巨大的差值之间,一定代表 \(2^n\) 个数会有重复,去重之后就可以得到 \(2^k\) 个数,说明每个数重复出现 \(2^{n-k}\) 次。
是不是十分感性,但是似乎也只能这么说了
对于这道题,我们只需要看一下 \(Q\) 到底是排名为多少的数,得到其排名 \(rk\) 之后,直接输出 \(rk\times 2^{n-k}+1\) 即可。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair< int,int >
#define Endl putchar('\n')
// #define int long long
// #define int unsigned
// #define int unsigned long long
#define cg (c=getchar())
template<class T>inline void qread(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
template<class T>inline T qread(const T sample){
T x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
#undef cg
// template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){//just short,int and long long
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);
putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}
const int MAXN=1e5;
const int MOD=10086;
template<class T>struct Basic{
#define MAXSIZE 62
T f[MAXSIZE+5],g[MAXSIZE+5];
int flg,siz;
//flg 记录插入时是否有不能放入的数
inline void clear(){
memset(f,0,sizeof f);flg=siz=0;
}
inline void insert(T num){
fep(i,MAXSIZE,0){
if(!(num>>i))continue;
if(!f[i]){f[i]=num;++siz;return;}
num^=f[i];
}
++flg;
}
inline T queryMax(T ret){
fep(i,MAXSIZE,0)if((ret^f[i])>ret)
ret^=f[i];
return ret;
}
inline T queryMin(){
if(flg)return 0;
T ret=(1ll<<MAXSIZE);
rep(i,0,MAXSIZE)ret=Min(ret,f[i]);
}
inline void buildg(){
rep(i,0,MAXSIZE)g[i]=f[i];
rep(i,0,MAXSIZE)rep(j,0,i-1)if(g[i]&(1ll<<j))
g[i]^=g[j];
}
inline T queryNum(T k){
//must build g before use it
if(flg)--k;
if(k==0)return 0;
T ret=0;
rep(i,0,MAXSIZE)if(g[i]){
if(k&1)ret^=g[i];
k>>=1;
}
return k?-1:ret;
}
};
Basic<LL>G;
inline int qkpow(int a,int n,const int mod){
int ret=1;
for(;n>0;n>>=1){
if(n&1)ret=ret*a%mod;
a=a*a%mod;
}
return ret;
}
int pos[MAXSIZE+5],cnt,n;
LL Q,ans;
signed main(){
n=qread(1);
rep(i,1,n)G.insert(qread(1ll));
Q=qread(1ll);
rep(i,0,62)if(G.f[i])pos[cnt++]=i;
rep(i,0,cnt-1)if(Q&(1ll<<pos[i]))
(ans|=(1<<i))%=MOD;
printf("%lld\n",((ans%MOD*qkpow(2,n-G.siz,MOD))+1)%MOD);
//不能直接用左移,因为会爆 long long
return 0;
}