码迷,mamicode.com
首页 > 其他好文 > 详细

[HAOI2015]按位或——Min-Max容斥+FWT

时间:2020-03-02 11:00:52      阅读:45      评论:0      收藏:0      [点我收藏+]

标签:end   ace   容斥   scanf   $1   等于   sum   图片   one   

题面

  Bzoj4036

解析

  考虑$ans=E(max(t[i])), i\in S, S=\begin{Bmatrix} 1,2,\cdots, n\end{Bmatrix}$,这里$t[i]$表示第$i$位变成$1$的时间,$E(max(t[i]))$表示最后变成$1$的一位的期望时间,暂时记为$E(max(S))$,注意这个不等于$max(E(S))$

  然后套上$Min-Max$容斥,$ans=\sum_{T \subseteq S}E(min(T))$,$E(min(T))$表示$T$中至少有一位变成$1$的期望时间。

  $E(min(T))$似乎不太好求,考虑补集转换,$E(min(T))=\frac{1}{1-\sum_{i\cap T=\varnothing }p[i]}$,$p$为题目中给出的数组,若将$T$视为二进制数,则$E(min(T))=\frac{1}{1-\sum_{i\&T=0}p[i]}$

  而$\sum_{i\&T==0}p[i]$就等于$T$的补集的子集和,因此只需要$FWT(or)$一次就可以了。

 代码:

技术图片
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = (1 << 20) + 5;
const double eps = 1e-11;

int n, m, num[maxn];
double a[maxn];
bool used[25];

void FWT_or(double *x)
{
    for(int i = 1; i <= m; i <<= 1)
        for(int j = 0; j <= m; j += (i << 1))
            for(int k = 0; k < i; ++k)
                x[i+j+k] += x[j+k];
}

int main()
{
    scanf("%d", &n);
    m = (1 << n) - 1;
    for(int i = 0; i <= m; ++i)
    {
        scanf("%lf", &a[i]);
        num[i] = num[i>>1] + (i & 1);
        if(a[i] > eps)
        {
            for(int j = 0; j < n; ++j)
                if((i >> j) & 1)
                    used[j] = 1;
        }
    }
    for(int j = 0; j < n; ++j)
        if(!used[j])
        {
            printf("INF");
            return 0;
        }
    FWT_or(a);
    double ans = 0;
    for(int i = 1; i <= m; ++i)
        ans += ((num[i] & 1)? 1: -1) / (1 - a[m^i]);
    printf("%.10f", ans);
    return 0;
}
View Code

 

[HAOI2015]按位或——Min-Max容斥+FWT

标签:end   ace   容斥   scanf   $1   等于   sum   图片   one   

原文地址:https://www.cnblogs.com/Joker-Yza/p/12393764.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!