【BZOJ】3925 [Zjoi2015]地震后的幻想乡 状压+期望DP||定积分

80 篇文章 0 订阅
30 篇文章 0 订阅

题目传送门

这题是真的神仙题……整整花了我两个礼拜来理解这题

首先这题据我了解有三种做法:纯OI做法、积分+数学推导、直接积分

请做好一定的心理准备,接下来的东西可能有点难理解(好像不是一点点的难吧……)


1.纯OI做法

首先我们根据期望的线性性,可以得到 a n s = ∑ x = 0 m w ( x ) × p ( x ) ans=\sum_{x=0}^mw(x)\times p(x) ans=x=0mw(x)×p(x),其中 w ( x ) w(x) w(x)为最大边为 x x x时的对答案的贡献, p ( x ) p(x) p(x)为最大边为 x x x时的概率。

由题目所给信息“对于 n n n个之 [ 0 , 1 ] [0,1] [0,1]间的随机变量 x 1 , x 2 , . . . , x n x1,x2,...,xn x1,x2,...,xn,第 k k k小的那个的期望值是 k n + 1 \frac{k}{n+1} n+1k”可知: w ( x ) = x m + 1 w(x)=\frac{x}{m+1} w(x)=m+1x

∴ a n s = ∑ x = 0 m x m + 1 × p ( x ) \therefore ans=\sum_{x=0}^m\frac{x}{m+1}\times p(x) ans=x=0mm+1x×p(x)

f ( x ) f(x) f(x)为最大边权的排名 ≥ x \ge x x的概率,则 p ( x ) = f ( x − 1 ) − f ( x ) p(x)=f(x-1)-f(x) p(x)=f(x1)f(x)

∴ a n s = 1 m + 1 × [ f ( 0 ) − f ( 1 ) ] + 2 m + 1 × [ f ( 1 ) − f ( 2 ) ] + . . . + m m + 1 × [ f ( m − 1 ) − f ( m ) ] + m + 1 m + 1 × [ f ( m ) − f ( m + 1 ) ] \therefore ans=\frac{1}{m+1}\times[f(0)-f(1)]+\frac{2}{m+1}\times[f(1)-f(2)]+...\\+\frac{m}{m+1}\times[f(m-1)-f(m)]+\frac{m+1}{m+1}\times[f(m)-f(m+1)] ans=m+11×[f(0)f(1)]+m+12×[f(1)f(2)]+...+m+1m×[f(m1)f(m)]+m+1m+1×[f(m)f(m+1)]

∵ f ( 0 ) = 1 , f ( m + 1 ) = 0 \because f(0)=1,f(m+1)=0 f(0)=1,f(m+1)=0
∴ a n s = 1 m + 1 ∑ x = 0 m f ( x ) \therefore ans=\frac{1}{m+1}\sum_{x=0}^mf(x) ans=m+11x=0mf(x)
定义 f [ S ] [ i ] f[S][i] f[S][i]为点集为 S S S,选取了 i i i条边使得点集不连通的方案数;同理,定义 g [ S ] [ i ] g[S][i] g[S][i]为点集为 S S S,选取了 i i i条边使得点集连通的方案数。

易得 f [ S ] [ i ] + g [ S ] [ i ] = ( i c n t [ s ] ) f[S][i]+g[S][i]={i\choose cnt[s]} f[S][i]+g[S][i]=(cnt[s]i),其中 c n t [ S ] cnt[S] cnt[S]为点集 S S S内的边数。

可以通过固定某定点 P P P来进行转移,以达到不重复、不遗漏的计数。
f [ S ] [ i + j ] = ∑ P ∈ S , T ⊂ S g [ T ] [ i ] × ( j c n t [ S − T ] ) f[S][i+j]=\sum_{P \in S,T \subset S}g[T][i]\times{j \choose cnt[S-T]} f[S][i+j]=PS,TSg[T][i]×(cnt[ST]j)
那么最终答案即为 a n s = 1 m + 1 ∑ x = 0 m f [ a l l ] [ x ] ( x c n t [ a l l ] ) ans=\frac{1}{m+1}\sum_{x=0}^m\frac{f[all][x]}{x \choose cnt[all]} ans=m+11x=0m(cnt[all]x)f[all][x]

附上AC代码:

#include <cstdio>
using namespace std;

typedef long long ll;
const int N=11,M=46;
int n,m,e[N],sz[1<<N],cnt[1<<N],wz;
ll c[M][M],f[1<<N][M],g[1<<N][M];
double ans;

int main(void){
	scanf("%d%d",&n,&m);
	for (int i=1,x,y; i<=m; ++i) scanf("%d%d",&x,&y),--x,--y,e[x]|=1<<y,e[y]|=1<<x;
	c[0][0]=1;
	for (int i=1; i<=m; ++i){
		c[i][0]=1;
		for (int j=1; j<=i; ++j) c[i][j]=c[i-1][j-1]+c[i-1][j];
	}
	for (int sub=1; sub<(1<<n); ++sub){
		if ((sz[sub]=sz[sub>>1]+(sub&1))==1){g[sub][0]=1; continue;}
		for (int i=0; i<n; ++i) if ((sub>>i)&1) cnt[sub]+=sz[e[i]&sub];
		cnt[sub]>>=1,wz=sub&-sub;
		for (int opt=(sub-1)&sub; opt; opt=(opt-1)&sub)
			if (opt&wz)
				for (int i=0; i<=cnt[opt]; ++i)
					for (int j=0; j<=cnt[opt^sub]; ++j)
						f[sub][i+j]+=g[opt][i]*c[cnt[opt^sub]][j];
		for (int i=0; i<=cnt[sub]; ++i) g[sub][i]=c[cnt[sub]][i]-f[sub][i];
	}
	for (int i=0; i<=m; ++i) ans+=(double)f[(1<<n)-1][i]/c[cnt[(1<<n)-1]][i];
	return printf("%.6lf\n",ans/=m+1),0;
}

接下来的两种做法可能需要一定的高等数学知识,至于定积分、求导之类的运算法则,出门左拐度娘处。

讲接下来的两种做法之前,我们先来证明一个对于我个人很难理解的东西,因为接下来的做法都要用到。

求证: a n s = ∫ 0 1 f ( x ) d x ans=\int_0^1f(x){\rm d}x ans=01f(x)dx,其中 f ( x ) f(x) f(x)为答案 &gt; x &gt;x >x的概率。

证明:设 p ( x ) p(x) p(x)为答案 = x =x =x的概率

易得: p ( x ) = lim ⁡ Δ x → 0 f ( x ) − f ( x + Δ x ) Δ x = − f ′ ( x ) p(x)=\lim_{\Delta x \rightarrow 0}\frac{f(x)-f(x+\Delta x)}{\Delta x}=-f&#x27;(x) p(x)=limΔx0Δxf(x)f(x+Δx)=f(x)

根据期望的定义,得: a n s = ∫ 0 1 x × p ( x ) d x ans=\int_0^1x\times p(x){\rm d}x ans=01x×p(x)dx

∴ a n s = ∫ 0 1 x × ( − f ′ ( x ) ) d x = ∫ 0 1 x d ( − f ( x ) ) = [ x × ( − f ( x ) ) ] 0 1 + ∫ 0 1 f ( x ) d x \therefore ans=\int_0^1x\times (-f&#x27;(x)){\rm d}x=\int_0^1x{\rm d}(-f(x))=[x\times (-f(x))]_0^1+\int_0^1f(x){\rm d}x ans=01x×(f(x))dx=01xd(f(x))=[x×(f(x))]01+01f(x)dx

∵ f ( x ) \because f(x) f(x)为答案 &gt; x &gt;x >x的概率 ∴ f ( 0 ) = 1 , f ( 1 ) = 0 ∴ a n s = ∫ 0 1 f ( x ) d x \qquad\therefore f(0)=1,f(1)=0\qquad\therefore ans=\int_0^1f(x){\rm d}x f(0)=1,f(1)=0ans=01f(x)dx

证毕。

2.积分+数学推导

我们设一个函数 P S ( t ) P_S(t) PS(t)表示当 S S S[ S S S为一个点集在原图中的导出子图]中的最大边为 t t t时, S S S不连通的概率为 P S ( t ) P_S(t) PS(t)

那么有 E ( X ) = ∫ 0 1 P S I E ( t ) d t E(X)=\int_0^1P_{SIE}(t){\rm d}t\qquad E(X)=01PSIE(t)dt[ S I E SIE SIE为全集] \qquad (根据上面的证明可得)

我们可以方便地写出 P ( t ) P(t) P(t)的递归式。

我们考虑一张图 S S S,我们把其分成两部分( S 0 S_0 S0 S − S 0 S-S_0 SS0),那么 S 0 S_0 S0连通而 S S S不连通的概率为:
[ 1 − P S 0 ( t ) ] × ( 1 − t ) E ( S 0 , S ) [1-P_{S_0}(t)]\times(1-t)^{E(S_0,S)} [1PS0(t)]×(1t)E(S0,S)
其中 E ( S 0 , S ) E(S_0,S) E(S0,S) S 0 S_0 S0 S − S 0 S- S0 SS0的边数。
∴ P S ( t ) = ∑ S 0 ̸ ⊆ S ( 1 − t ) E ( S 0 , S ) × [ 1 − P S 0 ( t ) ] [ 1 ∈ S 0 ] ∴ E ( X ) = ∫ 0 1 P S I E ( t ) d t = ∫ 0 1 ∑ ( 1 − t ) E ( S 0 , S ) × [ 1 − P S 0 ( t ) ] ] d t [ 1 ∈ S 0 ) ] = ∑ ∫ 0 1 ( 1 − t ) E ( S 0 , S ) d t − ∫ 0 1 ( 1 − t ) E ( S 0 , S ) × P S 0 ( t ) d t = ∑ 1 E ( S 0 , S ) + 1 − ∫ 0 1 ( 1 − t ) E ( S 0 , S ) × P S 0 ( t ) d t \begin{aligned} \therefore P_S(t)&amp;=\sum_{S_0\not\subseteq S}(1-t)^{E(S_0,S)}\times [1-P_{S_0}(t)]\qquad[1\in S_0]\\ \therefore E(X)&amp;=\int_0^1P_{SIE}(t){\rm d}t\\ &amp;=\int_0^1\sum(1-t)^{E(S_0,S)}\times[1-P_{S_0}(t)]]{\rm d}t\qquad[1\in S_0)]\\ &amp;=\sum\int_0^1(1-t)^{E(S_0,S)}{\rm d}t-\int_0^1(1-t)^{E(S_0,S)}\times P_{S_0}(t){\rm d}t\\ &amp;=\sum\frac{1}{E(S_0,S)+1}-\int_0^1(1-t)^{E(S_0,S)}\times P_{S_0}(t){\rm d}t \end{aligned} PS(t)E(X)=S0̸S(1t)E(S0,S)×[1PS0(t)][1S0]=01PSIE(t)dt=01(1t)E(S0,S)×[1PS0(t)]]dt[1S0)]=01(1t)E(S0,S)dt01(1t)E(S0,S)×PS0(t)dt=E(S0,S)+1101(1t)E(S0,S)×PS0(t)dt

我们递归定义 f [ S 0 ] [ E ( S 0 , S ) ] = ∫ 0 1 ( 1 − t ) E ( S 0 , S ) × P S 0 ( t ) d t ​ f[S_0][E(S_0,S)]=\int_0^1(1-t)^{E(S_0,S)}\times P_{S_0}(t){\rm d}t​ f[S0][E(S0,S)]=01(1t)E(S0,S)×PS0(t)dt

∴ f [ 1 ] [ k ] = 0 , k ∈ [ 0 , m ] f [ S ] [ k ] = ∑ 1 k + E ( S 0 , S ) + 1 − f [ S 0 ] [ k + E ( S 0 , S ) ] \therefore f[1][k]=0,k\in[0,m]\qquad f[S][k]=\sum\frac{1}{k+E(S_0,S)+1}-f[S_0][k+E(S_0,S)] f[1][k]=0,k[0,m]f[S][k]=k+E(S0,S)+11f[S0][k+E(S0,S)]

然后直接暴力即可。

附上AC代码:

#include <cstdio>
using namespace std;

const int N=11,M=56;
int n,m,x,y,t[1<<N][1<<N],all,b[1<<N][M];
double f[1<<N][M];

inline double calc(int sub,int k){
	if (sub==1) return 0;
	if (b[sub][k]) return f[sub][k];
	b[sub][k]=1;
	double &ans=(f[sub][k]=.0);
	for (int opt=(sub-1)&sub; opt^sub; opt=(opt-1)&sub)
		if (opt&1) ans+=1.0/(k+t[opt][sub&~opt]+1),ans-=calc(opt,k+t[opt][sub&~opt]);
	return ans;
}

int main(void){
	scanf("%d%d",&n,&m),all=(1<<n)-1;
	while (m--){
		scanf("%d%d",&x,&y),--x,--y;
		for (int s1=0; s1<=all; ++s1)
			if ((s1>>x)&1)
				for (int s2=0; s2<=all; ++s2)
					if ((s2>>y)&1)
						++t[s1][s2],++t[s2][s1];
	}
	return printf("%.6lf\n",calc(all,0)),0;
}

3.直接积分

首先记 F ( x ) F(x) F(x)为答案 &gt; x &gt;x >x的概率,可知 a n s = ∫ 0 1 F ( x ) d x ans=\int_0^1F(x){\rm d}x ans=01F(x)dx

F ( x ) F(x) F(x)等价于边权 &lt; x &lt;x <x时不能使图连通的概率。有点难求,正难则反,考虑使图连通的概率。

f ( S ) f(S) f(S)为集合 S S S连通的概率, f ( S ) = 1 − ∑ S ′ ⊂ S f ( S ′ ) × ( 1 − x ) c n t f(S)=1-\sum_{S&#x27;\subset S}f(S&#x27;)\times(1-x)^{cnt} f(S)=1SSf(S)×(1x)cnt,其中 c n t cnt cnt S ′ S&#x27; S S − S ′ S-S&#x27; SS的边数。

可以发现, f ( S ) f(S) f(S)为关于 x x x的多项式,可以做定积分。

也可以换一种理解的方式。

f ( x ) f(x) f(x) x = = a n s x==ans x==ans的概率密度函数,令 F ( x ) = ∫ f ( x ) d x F(x)=\int f(x){\rm d}x F(x)=f(x)dx
a n s = ∫ 0 1 x f ( x ) d x = ∫ 0 1 x d ( F ( x ) ) = [ x × F ( x ) ] 0 1 − ∫ 0 1 F ( x ) d x = 1 − ∫ 0 1 F ( x ) d x = ∫ 0 1 ( 1 − F ( x ) ) d x \begin{aligned} ans&amp;=\int_0^1xf(x){\rm d}x\\ &amp;=\int_0^1x{\rm d}(F(x))\\ &amp;=[x\times F(x)]_0^1-\int_0^1F(x){\rm d}x\\ &amp;=1-\int_0^1F(x){\rm d}x\\ &amp;=\int_0^1(1-F(x)){\rm d}x \end{aligned} ans=01xf(x)dx=01xd(F(x))=[x×F(x)]0101F(x)dx=101F(x)dx=01(1F(x))dx
F ( x ) F(x) F(x)的意义为取值 ≤ x \le x x的概率,等价于每条边有 x x x的概率出现,问图的连通概率。

注意:这种做法不知为何有点卡精度,需要开__float128。

#include <cstdio>
#include <vector>
using namespace std;

const int N=10,M=57;
typedef __float128 ld;
typedef long long ll;
typedef vector <ll> poly;
struct note{
	int x,y;
}a[M];
int n,m;
poly o,tmp,f[1<<N],ans;

inline bool in(int x,int sub){return (sub>>x-1)&1;}

inline poly operator * (const poly x,const poly y){
	poly ret(x.size()+y.size()-1,0);
	for (int i=0; i<x.size(); ++i)
		for (int j=0; j<y.size(); ++j)
			ret[i+j]+=x[i]*y[j];
	return ret;
}

inline poly operator - (const poly x,const poly y){
	poly ret(max(x.size(),y.size()),0);
	for (int i=0; i<x.size(); ++i) ret[i]+=x[i];
	for (int i=0; i<y.size(); ++i) ret[i]-=y[i];
	return ret;
}

inline ld integrate(poly ans){
	ld ret=0;
	for (int i=0; i<ans.size(); ++i) ret+=ld(1.0)*ans[i]/(i+1);
	return ret;
}

int main(void){
	scanf("%d%d",&n,&m);
	for (int i=1; i<=m; ++i) scanf("%d%d",&a[i].x,&a[i].y);
	o.push_back(1),o.push_back(-1),f[1].push_back(1);
	for (int sub=3; sub<(1<<n); sub+=2){
		f[sub].clear(),f[sub].push_back(1);
		for (int opt=(sub-1)&sub; opt; opt=(opt-1)&sub)
			if (opt&1){
				int cnt=0;
				for (int i=1; i<=m; ++i)
					if (in(a[i].x,sub)&&in(a[i].y,sub)&&(in(a[i].x,opt)^in(a[i].y,opt))) ++cnt;
				for (tmp=f[opt]; cnt; --cnt) tmp=tmp*o;
				f[sub]=f[sub]-tmp;
			}
	}
	ans.push_back(1),ans=ans-f[(1<<n)-1];
	return printf("%.6f\n",(double)integrate(ans)),0;
}

还有一小部分没有弄懂,就是“对于 n ​ n​ n个之 [ 0 , 1 ] ​ [0,1]​ [0,1]间的随机变量 x 1 , x 2 , . . . , x n ​ x1,x2,...,xn​ x1,x2,...,xn,第 k ​ k​ k小的那个的期望值是 k n + 1 ​ \frac{k}{n+1}​ n+1k”的证明,最近还在思考,挖坑待填。

淦,凭什么一个多项式做定积分会有阶乘这种东西出来,不知道为什么 ∫ 0 1 x k ( 1 − x ) n − k d x = k ! 1 ! ( n − k ) ! ( n + 1 ) ! \int_0^1x^k(1-x)^{n-k}{\rm d}x=\frac{k!1!(n-k)!}{(n+1)!} 01xk(1x)nkdx=(n+1)!k!1!(nk)!,还是留坑待填。

至于第 k k k小的概率好像已经石锤了, p ( x ) = n × ( n − 1 k − 1 ) × x k − 1 ( 1 − x ) n − k p(x)=n\times {n-1 \choose k-1} \times x^{k-1}(1-x)^{n-k} p(x)=n×(k1n1)×xk1(1x)nk

有没有哪位巨佬可以教我一下的,希望在评论区留言,锅在这里很难受的嘤嘤嘤。

UPD:也许我已经会证明了,找到一个写的比较详细的人:巨佬传送门,证明过程等我笔记本修好再好好写一下吧。


后记:讲真,这的确是一道神题,很有思考的价值。

连续性变量的期望用微积分的方法来做会简便很多。

希望我写的博客能够帮助各位巨佬解这道题,另外我不觉得信息学和微积分有何冲突,只要是能做题的方法都是好方法,并没有哪种方法好一些,不应该有偏见,能掌握做题的方法肯定是越多越好。

就这样吧。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值