[HAOI2015]按位或

一、题目

点此看题

二、解法

m a x ( S ) max(S) max(S)表示组成 S S S的最后一个元素的出现时间, m i n ( S ) min(S) min(S)表示组成 S S S的第一个元素的出现时间,这个是用时间顺序作为大小关系的,所以可以套用 min-max \text{min-max} min-max容斥,下文的 E E E表示期望, U U U表示全集,我们要求的是 E ( m a x ( U ) ) E(max(U)) E(max(U))
E ( m a x ( U ) ) = ∑ S ≠ ∅ ( − 1 ) ∣ s ∣ − 1 E ( m i n ( S ) ) E(max(U))=\sum_{S\not=\empty}(-1)^{|s|-1}E(min(S)) E(max(U))=S=(1)s1E(min(S))关键在于如果快速求 E ( m i n ( S ) ) E(min(S)) E(min(S))了,设 p ( m i n ( S ) = i ) p(min(S)=i) p(min(S)=i)表示这个出现时间为 i i i的概率,那么:
E ( m i n ( S ) ) = ∑ i = 1 + ∞ i × p ( m i n ( S ) = i ) E(min(S))=\sum_{i=1}^{+\infty}i\times p(min(S)=i) E(min(S))=i=1+i×p(min(S)=i)现在考虑如何计算 p ( m i n ( S ) = i ) p(min(S)=i) p(min(S)=i),我们前 i − 1 i-1 i1个时间选不到,正好在 i i i时间选到:
p ( m i n ( S ) = i ) = ( ∑ T ∩ S = ∅ a [ T ] ) i − 1 ( 1 − ∑ T ∩ S = ∅ a [ T ] ) p(min(S)=i)=(\sum_{T\cap S=\empty}a[T])^{i-1}(1-\sum_{T\cap S=\empty}a[T]) p(min(S)=i)=(TS=a[T])i1(1TS=a[T])方便推导,我们设 x = ∑ T ∩ S = ∅ a [ T ] x=\sum_{T\cap S=\empty}a[T] x=TS=a[T],把上面的式子带到 E ( m i n ( S ) ) E(min(S)) E(min(S))中去,可以发现:
E ( m i n ( S ) ) = ∑ i = 1 + ∞ i ( x ) i − 1 ( 1 − x ) = ∑ i = 1 ∞ i x i − 1 − i x i E(min(S))=\sum_{i=1}^{+\infty}i(x)^{i-1}(1-x)=\sum_{i=1}^{\infty}ix^{i-1}-i x^{i} E(min(S))=i=1+i(x)i1(1x)=i=1ixi1ixi仔细观察一下,就会化成这个形式:
E ( m i n ( S ) ) = ∑ i = 0 ∞ x i = 1 1 − x = 1 1 − ∑ T ∩ S = ∅ a [ T ] E(min(S))=\sum_{i=0}^{\infty}x^i=\frac{1}{1-x}=\frac{1}{1-\sum_{T\cap S=\empty}a[T]} E(min(S))=i=0xi=1x1=1TS=a[T]1其实吧, ∑ T ∩ S = ∅ a [ T ] = ∑ T ⊆ C U S a [ T ] \sum_{T\cap S=\empty}a[T]=\sum_{T\subseteq C_US}a[T] TS=a[T]=TCUSa[T],这显然就是 o r or or卷积可以求出来的东西,套板子预处理,然后用第一个式子算就行了,时间复杂度 O ( n 2 n ) O(n2^n) O(n2n)

#include <cstdio>
#define db double
const int M = 1<<20;
int read()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
    return num*flag;
}
int n,m,bit[M];db ans,a[M];
void fwt(db *a,int n,int op)
{
	for(int i=1;i<n;i<<=1)
		for(int p=i<<1,j=0;j<n;j+=p)
			for(int k=0;k<i;k++)
			{
				if(op==1) a[i+j+k]=a[i+j+k]+a[j+k];
				else a[i+j+k]=a[i+j+k]-a[j+k];
			}
}
int main()
{
	n=read();m=1<<n;
	for(int i=0;i<m;i++)
	{
		scanf("%lf",&a[i]);
		bit[i]=bit[i>>1]+(i&1);
	}
	fwt(a,m,1);
	for(int i=1;i<m;i++)
	{
		int Cu=i^(m-1);
		if(1-a[Cu]<1e-8)
		{
			puts("INF");
			return 0;
		}
		db v=1.0/(1.0-a[Cu]);
		ans+=(bit[i]%2?1:-1)*v;
	}
	printf("%.10lf\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值