按位或:多项式,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 }
一道神奇的代码只有343B的黑题
posted @ 2019-12-10 19:15  DeepinC  阅读(311)  评论(0编辑  收藏  举报