按位或:多项式,FWT,min-max容斥
Description:
刚开始你有一个数字0,每一秒钟你会随机选择一个$[0,2^n)$的数字,与你手上的数字进行或(C++, C 的
|
, Pascal 的or
)操作。选择数字i的概率是$p_i$ (保证$p \le p_i \le 1$,$\sum p_i =1$ )问期望多少秒后,你手上的数字变成$2^n-1$。($n \le 20$)
日常:想->问NC大聚聚这题有什么新知识点->学知识点->做->调。。。
全是新知识点,难度也都不低。一个知识点一道题也不知道自己是不是记住了。。。
最近写博客,基本每新写一道题的题解,就要新建至少一个Tag。。。
扯远了。
既然题目里都或起来了,那么就不难想到FWT。
但是连式子都没有FWT干什么啊???
然而关于集合期望这类题貌似是有一个套路的,就是min-max容斥。
min-max容斥的基本形式是:$max(S)=\sum\limits_{\phi \neq T \subseteq S} (-1)^{|T|+1} min(T)$
而且还满足于期望。即在min与max外套上一个E()依旧成立
这里的max是指在某一特定排序规则下,S集合中最大的元素。这种大小排序规则可以自己规定,只要有确定的大小关系可以用大小于号给所有元素排列就好。
把min和max倒置结果也是成立的。很好说,因为大小关系是可以你自己来定义的,你只要把关系反过来min和max就反过来了。
min-max容斥的神奇之处在于,它把求最大值与最小值之间进行了转换,当其中一者难求而另一种好求的时候,就可以进行转换。
对于这道题目,我们要求的是「全集的最后一个选中的元素」。直接求不能求,所以换求法。
设max(S)表示S集合中出现的最晚的元素出现的时间,min反之。
那么就能得到$max(2^n-1)=\sum\limits_{i=1}^{2^n-1} min(i) \times (-1)^{cntbit(i)+1}$
大多数题目里求出min要比求出max要简单。考虑一下怎么求:
现在我们要求的min(S)就表示期望抓几次能抓到S中含有的至少一个元素。
这不太好想,所谓正难则反,那么我们求期望连续抓几次都不包含T内的元素。这里的T是上面的S的补集。
这样的话要好求一些。根据数学期望知识我们知道,如果抓到T集合及其子集的概率是p,那么期望连续次数就是$\frac{1}{i-p}$(包含断掉之后的那一下)
现在的问题就在于怎么求出一个集合和它所有的子集的总概率。
然后我也不知道怎么想到的我只知道LNC特别巨,你既然是在学FWT你就试试FWT呗。
然后你就发现对原数列进行一次FWT所得到的新的数列的含义就是每个集合及其所有子集的和。
然后。。。就没了。。。
1 #include<cstdio> 2 double p[1<<20],ans;int n,lb[1<<20]; 3 main(){ 4 scanf("%d",&n);lb[0]=1; 5 for(int i=0;i<1<<n;++i)scanf("%lf",&p[i]),lb[i]=-lb[i^i&-i]; 6 for(int m=1;m<1<<n;m<<=1)for(int i=0;i<1<<n;i+=m<<1)for(int j=i;j<m+i;++j)p[m+j]+=p[j]; 7 for(int i=1;i<1<<n;++i)ans+=1/(1+1e-13-p[i^(1<<n)-1])*lb[i];printf(ans>1e13?"INF":"%lf\n",ans); 8 }