[HAOI2015]按位或
阿新 • • 發佈:2021-06-19
Link
Description
\(n\) 個元素,一共構成 \(2^n\) 個集合,每個集合 \(s\) 有一個被選中的概率 \(p_s\),保證 \(\sum_{s} p_s=1\)。選中一個集合後,集合裡所有元素的 tag 變為 1。問期望選多少次集合後,所有元素的 tag 都是 1。
Solution
一開始有一個並不正確的做法,認為每一位是獨立的,然後計算每一位被打上 tag 的期望時間,然後對所有時間取 max。可以這樣理解這個做法的錯誤所在,期望是對所有情況的平均估計,有些情況下,即使當前這個期望時間最大的元素被打上了 tag,也可能有其他元素沒有。所以直接取最大時間是錯的。
正確做法應該是將所有元素當做整體來考慮。\(E(max\{S\})\)
考慮 min-max 容斥,有
\[E(max\{S\})=\sum_{T\subseteq S} (-1)^{|T|-1} E(min\{T\}) \]\(E(min\{S\})\) 即為 \(S\) 中至少有一個元素被打上標記的期望時間。如果能快速求這個,那麼 \(E(max\{S\})\) 就能通過 \(O(2^n)\) 的暴力列舉求出。
容易發現有
\[E(min\{S\})=1+E(min\{S\})\sum_{S \cap T = \emptyset}p_T \]整理得到
\[E(min\{S\})=\frac{1}{1-\sum_{S \cap T = \emptyset}p_T} \]\(S\)
#include<stdio.h> #define db double const int N=20; int n,p,cnt[1<<N]; db a[1<<N],ans=0; int main(){ scanf("%d",&n); p=1<<n; for(int i=0;i<p;i++) scanf("%lf",&a[i]),cnt[i]=cnt[i>>1]+(i&1); for(int j=0;j<n;j++) for(int i=0;i<p;i++) if((1<<j)&i) a[i]+=a[i^(1<<j)]; for(int i=1;i<p;i++) if(1-a[(p-1)^i]>1e-8) ans+=((cnt[i]&1)? 1:-1)/(1-a[(p-1)^i]); if(ans>1e-8) printf("%.8lf",ans); else printf("INF"); }