[P3175][HAOI2015]按位或
某金牌爺給我們講了講多項式相關的題目,這是第一道。
本題我們發現一般的期望DP難以優化,但是我們可以基於下面這個式子進行計算:
ans=\sum_{i=0}^{\infty} (第i輪未結束的概率)
令cnt(x) 表示x的二進位制中1的個數。
我們可以來容斥一波。列舉每一個未結束的狀態,然後讓其他位置隨便取,再計算對答案的貢獻,可以得到下面這個式子:
ans=\sum_{k=0}^{\infty}\sum_{i=0}^{2^n-2} (\sum_{j\subseteq i}p_j)^k(-1)^{n-cnt(i)+1}
=\sum_{i=0}^{2^n-2}(-1)^{n-cnt(i)+1}\sum_{k=0}^{\infty}(\sum_{j\subseteq i}p_j)^k
=\sum_{i=0}^{2^n-2}(-1)^{n-cnt(i)+1}\frac{1}{1-\sum_{j\subseteq i}p_j}
我們只需要用FWT計算出對於所有的:
f(i)=\sum_{j\subseteq i}
那麼就可以直接計算答案了。
程式碼巨短:
\#include<bits/stdc++.h> using namespace std; const int MAX_N=1<<20|5; double p[MAX_N]; int n,cnt[MAX_N]; int main(){ scanf("%d",&n); for(int i=0;i<1<<n;++i) scanf("%lf",&p[i]); for(int step=0;step<n;++step) for(int i=0;i<1<<n;++i) if(i&1<<step) p[i]+=p[i^1<<step]; for(int i=0;i<1<<n-1;++i) if(fabs(p[i]-1)<=1e-8){ puts("INF"); return 0; } cnt[0]=0; double ans=0; for(int i=0;i<(1<<n)-1;++i){ if(i!=0) cnt[i]=cnt[i^(i&-i)]+1; if((n-cnt[i])&1) ans+=1/(1-p[i]); else ans-=1/(1-p[i]); } printf("%.8lf",ans); return 0; }