10
13
2016
0

[BZOJ2844] albus就是要第一个出场

第一次写线性基,借鉴了PoPoQQQ大神的程序

所以主要做法就不说了,就说一说后面$ans$到底具体是什么

因为我们求线性基是从大到小求所以数字会递减

首先我们像数位dp一样从大到小枚举now,确认一次最多能取多少

因为如果第$i$个数可以取,那么后面的所有线性基都可以在不取当前值的情况下一次取完,所以总共的取法数$ans+=Qpow(2,n-i)$

如果曾经取过一些线性基,那么总取法要加上1(因为之前统计的是绝对<Q的,所以要加上当前的一个)

然后我们得知还有m个自由基,也就是可以经过某些排列组合后进行抵消(等于没用)

所以我们直接确定每个数是否取就行了,所以总共的取法数$ans*=Qpow(2,m)$

最后加上1是因为0也是一种方案

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int N=100005,P=10086;

int n,a[N],Q,m,ans;

inline void Read(int &x){
static char ch;
while((ch=getchar())<'0' || ch>'9');
x=ch-'0';
while((ch=getchar())>='0' && ch<='9')x=(x<<3)+(x<<1)+ch-'0';
}

inline void Gauss(){
int t=0,r;
for(register int i=1<<30;i;i>>=1){
	for(register int j=t+1;(r=j)<=n;j++)if(a[j]&i)break;
	if(r==n+1)continue;
	swap(a[r],a[++t]);
	for(register int j=1;j<=n;j++)if(j!=t && (a[j]&i))a[j]^=a[t];
}
m=n-t;
n=t;
}

inline int Qpow(int x,int y){
int z=1;
while(y){
	if(y&1)z=z*x%P;
	x=x*x%P;
	y>>=1;
}
return z;
}

int main(){
freopen("2844.in","r",stdin);
freopen("2844.out","w",stdout);
Read(n);
for(register int i=1;i<=n;i++)Read(a[i]);
Gauss();
Read(Q);
int nw=0;
for(register int i=1;i<=n;i++){
	if((nw^a[i])<Q)nw^=a[i],ans=(ans+Qpow(2,n-i))%P;
}
if(Q)ans++;
ans=ans*Qpow(2,m)%P+1;
printf("%d\n",ans%P);
return 0;
}
Category: BZOJ | Tags: OI bzoj | Read Count: 719

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com