您的位置:首页 > 其它

bzoj 3811: 玛里苟斯 高斯消元&dfs

2016-05-09 18:17 225 查看
这道题目还要根据k来分类讨论。。。。

当k=1的时候,按位求贡献,然后发现答案就是所有数or起来再/2。

当k=2的时候,就真的要按位来了。。按照(x1+x2+...+xn)^2展开x1x1+x1x2+x1x3...+xnxn,枚举i,j表示后面式子的下标。然后一个数就变成(0/1,0/1)二元组,当选出的数二元组异或后为(1,1)的时候有2^(i+j)的贡献。显然根据k=1发现(1,1)概率应该是1/4,但特殊情况就是所有二元组都是(0,0)或者(1,1)的形式则概率为1/2。

当k>2的时候,显然每个数<=2^21,而如果一个数能通过别的数异或得到则没有用。维护一个线性基然后就只有22个数了,dfs即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 75
#define ll unsigned long long
using namespace std;

int n,flag; ll ans,res,mod,bin[M],a
,base[M]; bool f[M][M];
void calc(){
int i,j;
for (i=1; i<=n; i++)
for (j=31; j>=0; j--) if (a[i]&bin[j])
if (!base[j]){
base[j]=a[i]; break;
} else a[i]^=base[j];
for (j=n=0; j<32; j++) if (base[j]) a[++n]=base[j];
}
void solve1(){
int i,j,k,t;
for (i=0; i<32; i++)
for (j=1; j<=n; j++) f[i][j]=(a[j]&bin[i])?1:0;
for (i=0; i<32; i++)
for (j=0; j<32; j++){
for (k=1; k<=n; k++) if (f[i][k]) break;
if (k>n) continue;
for (k=1; k<=n; k++) if (f[j][k]) break;
if (k>n) continue;
t=0;
for (k=1; k<=n && !t; k++)
if (f[i][k]!=f[j][k]) t=1;
if (i+j-1-t<0) res++; else ans+=bin[i+j-1-t];
ans+=res>>1; res&=1;
}
printf("%llu",ans); puts(res?".5":"");
}
void dfs(int k,ll now){
if (k>n){
int i; ll u=0,v=1;
for (i=1; i<=flag; i++){
u*=now; v*=now;
u+=v>>n; v&=mod;
}
ans+=u; res+=v;
ans+=res>>n; res&=mod;
return;
}
dfs(k+1,now); dfs(k+1,now^a[k]);
}
void solve2(){
mod=bin
-1; dfs(1,0);
printf("%llu",ans); puts(res?".5":"");
}
int main(){
scanf("%d%d",&n,&flag); int i;
bin[0]=1; for (i=1; i<63; i++) bin[i]=bin[i-1]<<1;
for (i=1; i<=n; i++) scanf("%llu",&a[i]);
if (flag==1){
for (i=1; i<=n; i++) ans|=a[i];
printf("%llu",ans>>1); puts((ans&1)?".5":"");
return 0;
}
calc();
if (flag==2) solve1(); else solve2();
return 0;
}


by lych
2016.5.9
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: