CF698C题解

为什么 \(n,k \leq 20\)

我还以为是什么 \(n,k \leq 10^6\) 的厉害题/qd

看到这个队列操作很迷惑,但是仔细看看要操作 \(10^{100}\) 遍,所以我们可以直接将这个题意理解成在 \(n\) 个数里面选 \(k\) 个数的概率。

这就很简单了,因为 \(n \leq 20\),所以我们直接大力枚举包含 \(i\) 的子集,然后计算选到这个子集的概率,然后就没了。

这个东西很容易用子集 dp 来转移,子集的概率之和也可以使用 FWT 来计算。

记得特判某些情况会输出 nan

#include<cstdio>
#include<cmath>
int n,x,S,cnt,siz[1<<20];double ans[20],s[1<<20],P[1<<20];
signed main(){
	int i,k,len;
	scanf("%d%d",&n,&x);S=1<<n;s[0]=1;
	for(i=0;i^n;++i)scanf("%lf",P+(1<<i)),cnt+=P[1<<i]!=0;if(cnt<x)x=cnt;
	for(len=1;len^S;len<<=1)for(k=0;k^S;k+=len<<1)for(i=0;i^len;++i)P[i|k|len]+=P[i|k];
	for(i=0;i^S;++i){
		siz[i]=siz[i>>1]+(i&1);
		for(k=0;k^n;++k)if(i>>k&1)s[i]+=s[i^1<<k]*P[1<<k]/P[S-1^i^1<<k];
		if(siz[i]==x)for(k=0;k^n;++k)if(i>>k&1)ans[k]+=s[i];
	}
	for(i=0;i^n;++i)printf("%.9lf ",ans[i]);
}
posted @ 2022-01-11 15:11  Prean  阅读(64)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};