BZOJ4036 HAOI2015按位或(概率期望+容斥原理)
考虑min-max容斥,改为求位集合内第一次有位变成1的期望时间。求出一次操作选择了S中的任意1的概率P[S],期望时间即为1/P[S]。
考虑怎么求P[S]。P[S]=∑p[s] (s&S>0)=1-∑p[s] (s&S==0)。做一个高维前缀和即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; #define N (1<<20) int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } const double eps=1E-8; int n,t,s[N]; double p[N],ans; int main() { #ifndef ONLINE_JUDGE freopen("bzoj4036.in","r",stdin); freopen("bzoj4036.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=0;i<(1<<n);i++) { scanf("%lf",&p[i]); if (p[i]>eps) t|=i; } if (t!=(1<<n)-1) {cout<<"INF";return 0;} for (int i=0;i<n;i++) for (int j=0;j<(1<<n);j++) if (j&(1<<i)) p[j]+=p[j^(1<<i)]; for (int i=1;i<(1<<n);i++) { s[i]=s[i^(i&-i)]+1; if (s[i]&1) ans+=1/(1-p[(1<<n)-1^i]); else ans-=1/(1-p[(1<<n)-1^i]); } printf("%.6f",ans); }