题解 P3175 【[HAOI2015]按位或】

shadowice1984

2018-04-28 22:06:50

Solution

真的套路啊……,没啥好说的,这种题知道结论就秒出然后不知道结论就直接gg了 好了让我们来讲正解吧,这就是到纯数学题,没啥好说的…… ~~我知道胡乱设一坨变量然后倒来倒去非常没人性,但是数学题就是得耐下心来推式子啊……~~ # 本题题解 ## 前置芝士1:min-max容斥原理 所谓min-max容斥原理,其实就是两个很简单的等式 记$max(S)$为集合S中的最大值,$min(S)$为集合S中的最小值,$|S|$为集合$S$的元素数量,那么以下两个等式成立 ## $max(S)=\sum_{T\subseteq S}(-1)^{|T|+1}min(T)$ ## $min(S)=\sum_{T\subseteq S}(-1)^{|T|+1}max(T)$ 所谓的min-max容斥原理大概就是这两个简单的等式了,它真正暴力的地方在于我们就算根本没法进行大小比较,也可以仅通过加减法把max或者min以极其暴力的方式$O(2^n)$的枚举子集容斥出来 下面我们尝试着给出证明,这里只证明第一个等式好了,后边的可以自行推出 其实只需要证明一件事,就是除了$min(T)=max(S)$的那个值,其他的$min$值都被消掉了就可以了(这里说明一下,我们假定集合中的元素两两相异,如果存在相同的值的话,我们给其中几个加上一些eps扰动一下即可,反正不影响最值就是了) 先来说明$max(S)$的系数为什么是1,假设中S最大的元素是a,那么我们会发现只有$min({a})=max(S)$所以$max(S)$的系数必须是1 然后再说明为什么别的$min$都被消掉了,假设某个元素b的排名是k,那么$min(T)=b$当且仅当我们选出的集合是后n-k个的元素构成的集合的子集然后并上{b}得到的,我们会发现显然这样的集合有$2^{n-k}$种,而显然这其中恰有$2^{n-k-1}$中是有奇数个元素的,恰有$2^{n-k-1}$种是有偶数个元素的,两两相消自然就成0了,当然上述等式在k=n的时候不成立,但是此时剩下的刚好是最大值,所以证明完毕~ -------------------------- ## 一些推导 现在我们有了非常暴力的min-max定理了,让我们来看看我们可以干一些什么事 一个令人惊讶的事实是,min-max定理在期望下成立,我们记$E(max(S))$为集合中max值的期望,那么有 ## $E(max(S))=\sum_{T\subseteq S}(-1)^{|T|+1}E(min(T))$ ## $E(min(S))=\sum_{T\subseteq S}(-1)^{|T|+1}E(max(T))$ 好了我们现在发现如果认为某个位置变为1的步数是一个随机变量的话 那么$E(max(S))$可以认为是某个集合S中所有位置变成1的期望步数,因为最晚的位置都变成1了,所有的位置自然都变成1了 那么很现实的一个事情是,我们没法比较两个位置变成1的期望步数长短,所以我们要使用min-max容斥原理在一无所知的(也就是说没有办法比较大小)情况下的求出max来 但是我们必须有一个求出min的方式……否则min-max容斥就是白搭,也就是说我们需要求$E(min(T))$换句话说,集合T中至少有一个位置变成1的最早时间 ## 前置芝士2:离散随机变量的几何分布 先说啥叫离散随机变量 离散随机变量就是一个随机变量只可以取一些特定的不连续值,比如全体正整数之类的…… 那么我们描述一个离散随机变量的最朴素的方式就是列一个表……,打出每个值的概率,然后就可以描述一个离散随机变量的分布了 那么所谓的集合分布呢,就是这里有一个离散型随机变量X,满足 ## $P(x==k)=(1-p)^{k-1}p (k\in N^{+})$ 其中p是一个常量 然后我们就说这个离散型随机变量X服从带参数p的集合分布 然后不如让我来试着求一下一个服从几何分布的随机变量的期望? ## $E(X)=\sum_{i=1}^{+ \infty}iP(x==i)$ ## $=p\sum_{i=1}^{+ \infty} i(1-p)^{i-1}$ 然后我们发现这大概是一个等比数列\*等差数列的数列求和的式子 ~~运用一些基本的高中数学知识~~ 可以算出来是这个式子 ## $E(x)=p\frac{1}{(1-(1-p)^2}=p\frac{1}{p^2}=\frac{1}{p}$ 是不是很神奇? 好了有了这个我们可以做什么呢? _________ ## 另一些推导 书接上回,我们现在要求$E(min(T))$了 那么也就是说,集合T中至少有一个位置变为1的期望步数 那么我们可以发现$P(min(T)==k)$的意义就是前k-1次都没有选中这个集合中的哪怕一个数,换句话来讲,前k-1次都是选了这个集合补集的子集,然后第k次没有选这个集合补集的子集,可以列出这样一个式子,我们记P(S)为选中S子集的概率之和 ## $P(min(T)==k)=P(S\oplus T)^{k-1}(1-P(S \oplus T))$ 这是什么?我们发现$min(T)$服从系数为$(1-P(S\oplus T))$的几何分布! 然后期望直接套公式计算就行啦! 现在的问题是,怎么求P(T)呢? ## 前置芝士3:快速莫比乌斯变换(FMT) 简单来说,快速莫比乌斯变换就是快速傅里叶变换的一个兄弟…… 只不过FFT的卷积是和卷积,就是i+j=k,而FMT的卷积是i|j=k也就是按位或卷积 但是和fft繁杂的变换式不一样,我们的FMT的变换式非常简单,记$\hat{f}(x)$为$f(x)$在FMT后的第x项系数,那么有 ## $\hat{f}(x)=\sum_{T \subseteq x} f(x)$ 这是什么?这就是子集和! 更加令人兴奋的是,FMT可以分治,可以分治! 分治方法和FFT的分治方式几乎一样,但是唯一的不同就是不需要二进制平摊翻转置换,也不需要虚数运算,变换公式就是 ## $a_{i}=a_{i},a_{i+k}=a_{i}+a_{i+k}$ ## 最后的推导 然后问题已经显而易见了,我们只要对原概率数组求一遍FMT即可求出P(T)了 然后就直接min-max容斥即可,如果分母为0的话直接输出inf即可了 所以这道非常套路的FMT+min-max容斥就做完了~对了,真的是超级好写! 上代码吧~ ```C #include<cstdio> #include<algorithm> using namespace std;const int N=1048580;typedef double db;db eps=1e-10; int n;db a[N];db res;int up;int siz[N]; int main() { scanf("%d",&n);up=(1<<n); for(int i=0;i<up;i++)scanf("%lf",&a[i]); for(int k=1;k<up;k<<=1)\\FMT板子 for(int s=0;s<up;s+=k<<1) for(int i=s;i<s+k;i++) {db a0=a[i];db a1=a[i+k];a[i]=a0;a[i+k]=a0+a1;} for(int i=1;i<up;i++){siz[i]+=siz[i>>1]+(i&1);} for(int i=1;i<up;i++)\\min-max容斥 { if(1-a[(up-1)^i]<eps){printf("INF\n");return 0;} db ex=1/(1-a[(up-1)^i]);if(siz[i]%2){res+=ex;}else {res-=ex;} }printf("%.10lf",res);return 0;\\拜拜程序~ } ```