bzoj4036 [HAOI2015]按位或 FWT+min-max容斥

28 篇文章 0 订阅
9 篇文章 0 订阅

Description


刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数字,与你手上的数字进行或(c++,c的|,pascal
的or)操作。选择数字i的概率是p[i]。保证0<=p[i]<=1,Σp[i]=1问期望多少秒后,你手上的数字变成2^n-1。
n ≤ 20 n\le20 n20

Solution


考虑min-max容斥,我们枚举一次就选中的位记为T,问题在于求E(T)
不妨记 P ( T ) = ∑ R ∣ T ≠ ∅ p ( R ) P(T)=\sum\limits_{R|T\neq\empty}{p(R)} P(T)=RT̸=p(R),显然 E ( T ) = 1 P ( T ) E(T)=\frac{1}{P(T)} E(T)=P(T)1
考虑补集转化,记 U = ∁ ( T ) , U=\complement(T), U=(T),那么 P ( T ) = 1 − ∑ S ⊂ U p ( S ) P(T)=1-\sum\limits_{S\subset U}{p(S)} P(T)=1SUp(S)
这里求 ∑ T ⊂ S p ( T ) \sum\limits_{T\subset S}p(T) TSp(T)也就是子集和,实际上直接做一次FWT就可以了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>

const int N=1049576;

double p[N];

int c[N];

void FWT(double *a,int n) {
	for (int i=1;i<n;i<<=1) {
		for (int j=0;j<n;j+=(i<<1)) {
			for (int k=0;k<i;++k) {
				a[j+k+i]+=a[j+k];
			}
		}
	}
}

int main(void) {
	freopen("data.in","r",stdin);
	int n; scanf("%d",&n);
	int lim=1<<n;
	for (int i=0;i<lim;++i) {
		scanf("%lf",&p[i]);
		c[i]=c[i>>1]^(i&1);
	}
	FWT(p,lim);
	double ans=0;
	for (int i=1;i<lim;++i) {
		if ((1-p[(lim-1)^i])>1e-8) {
			ans+=(c[i]?(1.0):(-1.0))/(1-p[(lim-1)^i]);
		}
	}
	if (ans<1e-8) puts("INF");
	else printf("%.10lf\n", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值