[ZJOI2015]地震后的幻想乡

[ZJOI2015]地震后的幻想乡

给定一张图,每条边的边权在 \([0,1]\) 中随机,求最小生成树的最大边权的期望。

\(n\le 10,m\le \frac{n(n-1)}{2}\)

Solution

这个题大概代表了七月份的一点学习记录,今天准备整理一下。不过按照这个方法推下来好 easy(无脑) 啊

对于连续型随机变量,我们一般使用概率密度函数 \(f(x)\) 来描述它取值的概率,其一定区域的积分可以表示取值为连续的一段区间的概率。

例如,论证 \(\mathbb{E}(\max\{x_1,x_2...x_n\})=\frac{n}{n+1}\) 时,我们先定义 \(F(x)=\max\{x_1...x_n\}\le x\),那么容易得到 \(F(x)=x^n\)

我们不难观察到,\(F(x)\) 的导数就是其对应的密度函数 \(f(x)\)

所以我们得到 \(f(x)=x^{n-1}n\)

容易观察得到,我们计算的期望为:

\[\begin{aligned} &\int_0^1 xf(x)\cdot dx \\&=\int_0^1 x^nn\cdot dx \\&=\frac{n}{n+1} \end{aligned}\]

接下来我们考虑证明题面给出的性质,注意到我们计算的是集合的 \(\min_k\),所以我们可以考虑通过拓展 \(\min-\max\) 容斥来计算答案:

\[\begin{aligned} &E(\min_k(x))=\sum_{i=k}^n \binom{n}{i}\binom{i-1}{k-1}(-1)^{i-k}\frac{i}{i+1} \\&=k\sum_{i=k}^n \binom{n}{i}\binom{i}{k}(-1)^{i-k}\frac{1}{i+1} \\&={k}\binom{n}{k}\sum_{i=k}^n \binom{n-k}{i-k}(-1)^{i-k}\frac{1}{i+1} \\&={k} \binom{n}{k}\sum_{j=0}^{n-k} \binom{n-k}{j} (-1)^j \frac{1}{j+k+1} \end{aligned}\]

\(m=n-k\)

\[\begin{aligned} &{k} \binom{n}{k}\sum_{j=0}^{m} \binom{m}{j} (-1)^j \frac{1}{j+k+1} \\&={k} \binom{n}{k} \sum_{j=0}^m \binom{m}{j} (-1)^j \int_0^1 x^{j+k} \\&={k}\binom{n}{k}\sum_{j=0}^m \binom{m}{j}\int_0^1 x^k(-x)^j \\&={k}\binom{n}{k}\int_0^1 x^k\sum_j^m(-x)^j \binom{m}{j} \\&={k}\binom{n}{k}\int_0^1 x^k(1-x)^m \\&={k} \times \frac{n!}{k!(n-k)!}\times \frac{k!m!}{(m+k+1)!} \\&=\frac{k}{n+1} \end{aligned}\]

于是得证。

最后一步是分部积分的结论,下面也给出证明:

考虑:

\[\begin{aligned} &f(x)g(x)=\int f'(x)g(x)+\int f(x)g'(x) \\&\int f'(x)g(x)=f(x)g(x)-\int f(x)g'(x) \end{aligned}\]

\(B(a+b,b)=\int_0^1 x^a(1-x)^b\),那么不难发现:

  • \(f(x)=\frac{x^a}{a+1},g(x)=(1-x)^b\)

\[\begin{aligned} &B(a+b,b)=\int_0^1 f'(x)g(x) \\&=f(1)g(1)-\int_0^1 f(x)g'(x) \\&=-\int_0^1 \frac{x^{a+1}}{a+1}\times (-b(1-x)^{b-1}) \\&=\frac{b}{a+1}\int_0^1 x^{a+1}(1-x)^{b-1} \\&=\frac{b}{a+1}B(a+b,b-1) \end{aligned}\]

观察到 \(B(a+b,0)=\int_0^1 x^{a+b}=\frac{1}{a+b+1}\),不难得到 \(B(a+b,b)=\frac{b!}{(a+b+1)^{\underline{b+1}}}=\frac{a!b!}{(a+b+1)!}\)

至此,命题得证。


注意到答案是:

\[\int_0^1 dx\times P(X=x)x \]

构造 \(g(x)=P(X\le x)\),那么 \(P(X=x)\)\(g(x)\) 的导数。

于是答案即为:

\[\int_0^1 dx\cdot g'(x)x=g(x)x-\int_0^1 dx\cdot g(x) \]

不难发现答案即为:

\[1-\int_0^1 dx\cdot P(X\le x) \]

后者等价于仅保留小于 \(x\) 的边有此图联通。

可以基于这样的考量,我们给每条边赋予 \(0/1\) 的权值表示他是否小于等于 \(x\),如果为 \(1\) 那么小于等于 \(x\),不妨假设有 \(a\)\(1\) 边和 \((m-a)\)\(0\) 边,此时概率角度的贡献为:

\[x^a(1-x)^{m-a} \]

对于某个具体的 \(a\),我们相当于计算:

\[\int_0^1 x^a(1-x)^{m-a}=\frac{a!(m-a)!}{(m+1)!} \]

于是我们成功的再次通过分部积分将此问题转换为给边染色,恰好染 \(a\) 条黑色边使得这张图联通的方案数。

等价于求这张图的恰好 \(a\) 条边的联通子图的数量。

经典的容斥手段是对于子集 \(S\) 先任意保留边,在枚举 \(1\) 号点所在的连通块,这里我们还需要枚举 \(1\) 所在的连通块所保留的边数,此时外部的边数是固定的,然后转移,复杂度为 \(\mathcal O(3^n\cdot m^2)\)

不难发现转移的时候的卷积为子集卷积,可以通过 FWT 处理做到 \(\mathcal O(2^nn^2\cdot m^2)\),不过意义不大。

\(Code:\)

#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
int gi() {
	char cc = getchar() ; int cn = 0, flus = 1 ;
	while( cc < '0' || cc > '9' ) {  if( cc == '-' ) flus = - flus ; cc = getchar() ; }
	while( cc >= '0' && cc <= '9' )  cn = cn * 10 + cc - '0', cc = getchar() ;
	return cn * flus ;
}
const int N = 10 + 5 ; 
const int M = 60 ; 
int n, m, lim, g[1 << 11] ; 
long double f[1 << 11][M], C[M][M], fac[M] ; 
signed main()
{
	n = gi(), m = gi() ; int x, y ; 
	rep( i, 1, m ) 
		x = gi() - 1, y = gi() - 1, 
		++ g[(1 << x) | (1 << y)] ;
	lim = (1 << n) ;
	for(re int k = 1; k < lim; k <<= 1 ) 
	rep( i, 0, lim ) if(i & k) g[i] += g[i ^ k] ; 
	C[0][0] = 1, f[0][0] = 1, fac[0] = 1 ; 
	rep( i, 1, m ) rep( j, 0, i ) C[i][j] = (!j) ? 1 : C[i - 1][j - 1] + C[i - 1][j] ; 
	rep( i, 1, m + 1 ) fac[i] = fac[i - 1] * i ; 
	for(re int S = 1; S < lim; ++ S) {
		int p = n ;
		rep( j, 0, n - 1 ) if((1 << j) & S) { p = j ; break ; } 
		rep( j, 0, m ) f[S][j] = C[g[S]][j] ; 
		for(re int i = S; i; i = (i - 1) & S) {
			if((!(i & (1 << p))) || (i == S)) continue ; 
			int u = S ^ i, l = g[i], r = g[u] ; 
			rep( j, 0, l ) rep( k, 0, r ) 
			f[S][j + k] -= f[i][j] * C[r][k] ;
		}
	}
	long double Ans = 1 ; -- lim ; 
	rep( j, 0, m ) Ans -= f[lim][j] / fac[m + 1] * fac[j] * fac[m - j] ;
	printf("%.6Lf\n", Ans ) ; 
	return 0 ;
}
posted @ 2020-10-20 20:32  Soulist  阅读(159)  评论(0)    收藏  举报