您的位置:首页 > 其它

[清华集训2014]玛里苟斯(线性基+概率期望)

2018-05-27 12:41 441 查看

首先有一些前置引理:

1. 由期望的线性性,平方的期望不等于期望的平方,所以求k次方的期望时,需要记录1~k-1的期望,然后计算增量(OSU!),这个这题没用上。

2. 线性基是可以变成每个元素都是2的次幂的(rebuild操作,也是求张成空间第k大的做法)。有一个关键的结论,张成空间内所有元素(设为k个)的出现概率都为$\frac{1}{2^k}$,也就是所有可能出现的异或和都是等概率的。

3. n个球里随机选,选到奇数个的概率和偶数个的概率各为1/2。观察杨辉三角可发现,偶数行由于对称显然成立,奇数行根据上一行得到所以也成立。(显然n=1除外)。

然后这题就可以做了。

首先k>=3时,可以知道x<=2^21,也就是张成空间最大为2^21,这个可以直接暴力搜索所有元素统计。

这里可能会爆unsigned long long,根据引理二发现分母是固定的,所以我们只要维护一个带分数(即一个整数和一个小于分母的分子)即可。

最后答案一定要么是整数,要么是.5。

当k=1时,根据引理三可知,如果有一位上所有数均为0,则这一位贡献为0,否则贡献为$\frac{1}{2}\times 2^x$,直接做即可。

当k=2时,将异或和每一位拆开来分情况讨论,这部分是较为复杂的。

基本上就像下面这样。

https://www.geek-share.com/detail/2735554520.html

#include<cstdio>
#include<cstring>
#include<algorithm>
#define rep(i,l,r) for (int i=l; i<=r; i++)
typedef unsigned long long ull;
using namespace std;

const int N=200010;
int n,K,lp;
ull p[66],x;

struct P{
ull a[66]; int n;
void insert(ull v){
for (int i=63;~i && v;i--) if ((v>>i)&1){
if (!a[i]) {a[i]=v; n++; break;}
v^=a[i];
}
}
}b;

void solve1(){
ull ans=0;
for (int i=0;i<=63;i++){
bool flag=0;
for (int j=0;j<=63;j++) if ((b.a[j]>>i)&1) flag=1;
if (flag) ans+=1ll<<i;
}
printf("%llu",(ull)(ans/2));
if (ans&1) printf(".5");
}

void solve2(){
ull ans=0,res=0;
for (int i=0;i<=31;i++)
for (int j=0;j<=31;j++){
bool c1,c2,c3,c4; c1=c2=c3=c4=0;
for (int k=0;k<=31;k++){
if (((b.a[k]>>i)&1)==1 && ((b.a[k]>>j)&1)==1) c1=1;
if (((b.a[k]>>i)&1)==1 && ((b.a[k]>>j)&1)==0) c2=1;
if (((b.a[k]>>i)&1)==0 && ((b.a[k]>>j)&1)==1) c3=1;
if (((b.a[k]>>i)&1)==0 && ((b.a[k]>>j)&1)==0) c4=1;
}
if (!(c1 || c3) || !(c1 || c2)) continue;
if (!(c3 || c2))
if (i+j>0) ans+=(1ll<<(i+j-1)); else res+=2;
else
if (i+j>1) ans+=(1ll<<(i+j-2)); else res+=(1<<(i+j));
}
printf("%llu",ans+(res>>2));
if (res&3) printf(".5");
}

void solve3(){
for (int i=0;i<=63;i++) if (b.a[i]) p[lp++]=b.a[i];
ull ans=0,res=0;
for (int i=0;i<(1<<lp);i++){
ull now=0,x=0,y=1;
for (int j=0;j<lp;j++) if ((i>>j)&1) now^=p[j];
for (int j=0;j<K;j++)
x*=now,y*=now,x+=y>>lp,y=y&((1<<lp)-1);
res+=y; ans+=x;
}
printf("%llu",ans+(res>>lp));
if (res&((1<<lp)-1)) printf(".5");
}

int main(){
freopen("bzoj3811.in","r",stdin);
freopen("bzoj3811.out","w",stdout);
scanf("%d%d",&n,&K);
for (int i=1;i<=n;i++) scanf("%llu",&x),b.insert(x);
if (K==1) solve1();
else if (K==2) solve2(); else solve3();
return 0;
}

bzoj3811

 

 


 

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