[HAOI2015]按位或

Posted miracevin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2015]按位或相关的知识,希望对你有一定的参考价值。

朴素的

f[S]表示S到(1<<n)的期望次数

发现1的个数只增加不减少

所以可以类似拓扑序的图,然后枚举子集O(3^n)转移

没有优化的余地

 

另辟蹊径:

拆开每一位来看

t[i]表示第i位变成1的次数

ans=E(max(t[i]))

根据min-max容斥

得到:ans=∑E(t[i])-∑E(min(t[i],t[j]))+∑E(min(t[i],t[j],t[k])).....

考虑min(S)的含义:

使得这个S中的任意一位0变成1的期望次数!

操作一次变成1的概率tmp:(1-p(操作一次不包含S))

(这个用FMT)

(当然,可以直接计算操作一次包含S的概率,但是直接FMT会把0算上,,这个要特殊处理)

1/tmp就是期望次数

根据S的size的奇偶确定符号

 

代码:

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^‘0‘)
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;x=0;bool fl=false;
    while(!isdigit(ch=getchar()))(ch==-)&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=22;
double p[1<<20];
int sz[1<<20];
double ans;
int n;
int main(){
    rd(n);
    for(reg i=0;i<(1<<n);++i){
        scanf("%lf",&p[i]);
        sz[i]=sz[i>>1]+(i&1);
    }
    for(reg i=0;i<n;++i){
        for(reg j=0;j<(1<<n);++j){
        //    cout<<" i j "<<i<<" "<<j<<endl;
            if(j&(1<<i)) p[j]+=p[j^(1<<i)];
         }
    }
//    cout<<" FMT "<<endl;
    int s=(1<<n)-1;
    for(reg i=1;i<(1<<n);++i){
        int bu=s-i;
        double tmp;
    //    cout<<" bu "<<bu<<" p[bu] "<<p[bu]<<endl;
        if(p[bu]!=1.000) tmp=1/(1.0-p[bu]);
        else {
            puts("INF");
            return 0;
        }
        if(sz[i]&1){
            ans+=tmp;
        }else ans-=tmp;
    }
    printf("%.10lf",ans);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/1/4 22:15:10
*/

如果想到min-max容斥和式子

应该就比较好做了。

 

正难则反的原因是:

max要考虑最后一个变成1的次数,都要考虑上,太麻烦

min只要考虑第一个变成1的次数,有一个操作涉及S,就合法了。

 

以上是关于[HAOI2015]按位或的主要内容,如果未能解决你的问题,请参考以下文章

[HAOI2015] 按位或

bzoj4036 / P3175 [HAOI2015]按位或

[HAOI2015]按位或

[HAOI2015]按位或

LOJ#2127. 「HAOI2015」按位或

luogu P3175 [HAOI2015]按位或