[BZOJ]4036: [HAOI2015]按位或 min-max容斥+FWT

3 篇文章 0 订阅
0 篇文章 0 订阅

Description

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

Solution

考虑min-max容斥,问题转化为算出每个子集第一个出现元素的期望时间。对于一个子集 S S S,直接算所有与它有交的子集概率和不好算,补集转化一下,算与它没有交集的子集概率和,就是它的补集的所有子集。FWT就行了。

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int inf=2147483647;
const double eps=1e-9;
int n,one[1<<20];double a[1<<20],ans=0,s[20];
int main()
{
    scanf("%d",&n);
    for(int i=0;i<(1<<n);i++)scanf("%lf",&a[i]);
    one[0]=0;for(int S=1;S<(1<<n);S++)one[S]=one[S>>1]+(S&1);
    for(int S=1;S<(1<<n);S++)
    for(int i=0;i<n;i++)
    if(S&(1<<i))s[i]+=a[S];
    for(int i=0;i<n;i++)if(s[i]<eps)return puts("INF"),0;
    for(int i=0;i<n;i++)
    for(int S=0;S<(1<<n);S++)
    if(S&(1<<i))a[S]+=a[S^(1<<i)];
    for(int S=1;S<(1<<n);S++)
    if(one[S]&1)
    {
        double t=1.0-a[((1<<n)-1)^S];
        if(t>eps)ans+=1.0/t;
    }
    else
    {
        double t=1.0-a[((1<<n)-1)^S];
        if(t>eps)ans-=1.0/(1.0-a[((1<<n)-1)^S]);
    }
    printf("%.10lf",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值