ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[题解][YZOJ50074] 小 C 的岛屿

2022-05-31 16:33:41  阅读:118  来源: 互联网

标签:连通 cdot 题解 sum 岛屿 lfor YZOJ50074 LL mod


仅仅是对 \(O(n^4)\) 做法的一个记录。

简要题意

有 \(N\) 座岛屿,初始时没有边。每座岛屿都有一个概率值 \(p_i\) 和一个大小为 \(s_i\) 友好列表 \(A_i\) 。

小 \(c\) 站在 \(1\) 号岛屿,依次执行以下操作:

\((1)\) 设现在在岛屿 \(x\),有 \(p_x\) 的概率产生一条图中尚未存在的随机无向边,不会产生自环。

\((2)\) 如果此时所有岛屿仍未联通,她会在当前点的友好列表中,等概率随机选择一个,走到那座岛屿上。并把不满意度增加 \(1\),然后重复 \((1)\)。否则就结束这个过程

求她的期望不满意度,对一个 \(10^9+7\) 取模.

\(n\le 50\).

解题思路

思考后不难发现,状态只与当前的位置,以及边数相关,那么可以设状态:

\(e(x,i)\) 表示现在位于点 \(x\),图还差 \(i\) 条边连通,期望还要走多少步。

则最终答案是:

\[Ans = \sum_{i=1}^me(1, i)\cdot P(\text{恰好 }i\text{ 条边连通的概率}) \]

不难得到 \(e\) 之间的转移式:

\[e(x,i)=1+\frac{1}{s_x}\sum_{x\rightarrow y}p_x\cdot e(y,i-1)+(1-p_x)\cdot e(y,i) \]

如果分层高斯消元是 \(O(n^5)\),考虑设 \(e(x,i)=c(x)+\sum b(x,y)\cdot e(y,i-1)\) 来递推解决。

带入转移式可得:

\[\begin{aligned} e(x,i)=1+\frac{1}{s_x}\sum_{x\rightarrow y}p_x\cdot e(y,i-1)+(1-p_x)\cdot (\sum_{z=1}^nc(y)+b(y,z)\cdot e(z,i-1))\\ e(x,i)=1+\frac{p_x}{s_x}\sum_{x\rightarrow y}e(y,i-1)+\frac{(1-p_x)}{s_x}\cdot \sum_{x\rightarrow y}(c(y)+\sum_{z=1}^nb(y,z)\cdot e(z,i-1))\\ e(x,i)=1+\frac{(1-p_x)}{s_x}\cdot \sum_{x\rightarrow y}^nc(y)+\frac{p_x}{s_x}\sum_{x\rightarrow y}e(y,i-1)+\frac{(1-p_x)}{s_x}\cdot \sum_{x\rightarrow y}\sum_{z=1}^nb(y,z)\cdot e(z,i-1)\\ \end{aligned} \]

于是可以得到两个方程:

\[c(x)=1+\frac{(1-p_x)}{s_x}\cdot \sum_{x\rightarrow y}^nc(y) \]

\[b(x,z)=\frac{p_x}{s_x}[x\rightarrow z]+\frac{1-p_x}{s_x}\sum_{x\rightarrow y}b(y,z) \]

这样就可以在 \(O(n^4)\) 的高斯消元内得到所有的 \(b,c\),然后递推得到 \(e(1,i)\)。


接下来考虑如何计算恰好 \(i\) 条边连通的概率,其实要算的就是 \(n\) 个点 \(i\) 条边连通图的方案数。

这类问题的经典处理方式是用斯特林反演来容斥。

于是考虑划分连通块,不同块之间的边不能选择,同一块内的边可选可不选。

令至少 \(n\) 个连通块的方案数为 \(f(n)\),恰好 \(n\) 个连通块的方案数为 \(g(n)\),两者关系即为:

\[\begin{aligned} f(n)&=\sum_{i=n}\begin{Bmatrix}n\\i\end{Bmatrix}g(i)\\ g(n)&=\sum_{i=n}(-1)^{i-n}\begin{bmatrix}i\\n\end{bmatrix}f(i) \end{aligned} \]

而我们希望通过计算 \(f\) 得到 \(g(1)\),故 \(f(i)\) 的容斥系数为 \((-1)^{i-1}(i-1)!\)。

所以 \(i\) 条边, \(n\) 个点的连通图数量实际上为:

\[\sum_{G}(-1)^{c(G)-1}(c(G)-1)!{e(G) \choose i} \]

其中 \(G\) 需要取遍所有的 \(n\) 个点的,划分成了若干连通块的,每个连通块内连成了完全图的图,\(c(G)\) 表示 \(G\) 的连通块数量,\(e(G)\) 表示 \(G\) 的边数。

设 \(dp(i,j)\) 表示 \(i\) 个点,划分成了若干连通块,每个连通块内部连成完全图后边数和为 \(j\),的所有图带上容斥系数的 \((-1)^{c(G)-1}(c(G)-1)!\) 之和,于是考虑 \(dp(i,j)\) 的转移。

首先不难满足 \((-1)^{c(G)-1}\) 这个系数条件,转移的时候直接乘上 \(-1\) 的系数即可。

那么 \((c(G)-1)!\) 怎么办呢,注意到这个系数的含义在于,我们希望把同一种划分连通块的方式计算 \((c(G)-1)!\) 次,那么不妨赋初值时先确定 \(1\) 号点所在连通块大小,转移的时候枚举下一个连通块的大小为 \(k\),以 \(\dbinom{i+k-1}{k}\) 的系数重标号,这样除了 \(1\) 号点所在连通块位置一定排在第一个,其他的连通块会因为在转移时对于其添加顺序有区分,有 \((c(G)-1)!\) 种排列顺序,满足了我们的需要。

于是有如下转移式:

\[dp(i+k,j+\frac{k\cdot(k-1)}{2})\gets^{-} \sum_{k=1}^{n-i} dp(i,j)\cdot \binom{i+k-1}{k} \]

这样可以 \(O(n^4)\) 计算出 \(dp(n,i)\) ,然后 \(O(n^4)\) 直接算出 \(g(i)\),表示 \(n\) 个点 \(i\) 条边的连通图个数,那么也不难算恰好 \(i\) 条边连通的概率了。

namespace Gauss{
	int n, a[N][N], b[N];
	inline int get(int x){ return (LL) b[x] * qpow(a[x][x], mod - 2) % mod; }
	void init(int m){
		n = m;
		lfor(i, 1, n) b[i] = 0;
		lfor(i, 1, n) lfor(j, 1, n) a[i][j] = 0;
	}
	void solve(){
		lfor(i, 1, n){
			int inv = qpow(a[i][i], mod - 2);
			lfor(j, 1, n) if(i != j){
				int K = (LL) inv * a[j][i] % mod;
				lfor(k, 1, n) MOD(a[j][k] -= (LL) K * a[i][k] % mod);
				MOD(b[j] -= (LL) K * b[i] % mod);
			}
		}
	}
}
using Gauss :: get;
using Gauss :: init;
using Gauss :: solve;

void get_coef(){
	init(n);
	lfor(x, 1, n){
		Gauss :: b[x] = mod - 1;
		Gauss :: a[x][x] = mod - 1;
		int v = (LL) q[x] * qpow(s[x], mod - 2) % mod;
		lfor(j, 1, s[x]) Gauss :: a[x][a[x][j]] = v;
	}
	solve();
	lfor(x, 1, n) c[x] = get(x);

	lfor(z, 1, n){
		init(n);
		
		lfor(x, 1, n){
			int v = (LL) q[x] * qpow(s[x]) % mod;
			if(lnk[x][z]) Gauss :: b[x] = Mod(-(LL) p[x] * qpow(s[x]) % mod);
			Gauss :: a[x][x] = mod - 1;
			lfor(y, 1, n) if(lnk[x][y]) Gauss :: a[x][y] = v;
		}
		
		solve();
		lfor(x, 1, n) b[x][z] = get(x);
	}

	lfor(i, 1, m) lfor(x, 1, n){
		lfor(y, 1, n) MOD(e[x][i] += (LL) b[x][y] * e[y][i - 1] % mod - mod);
		MOD(e[x][i] += c[x] - mod);
	}
}

void get_prob(){
	lfor(i, 1, n) dp[i][C(i, 2)] = 1;
	lfor(i, 1, n) lfor(j, 0, m) if(dp[i][j]) lfor(k, 1, n - i) 
		MOD(dp[i + k][j + C(k, 2)] += -(LL) dp[i][j] * C(i + k - 1, k) % mod);
	lfor(i, 0, m) lfor(j, i, m)
		MOD(g[i] += (LL) dp[n][j] * C(j, i) % mod - mod);
	lfor(i, 1, m) g[i] = (LL) g[i] * qpow(C(m, i), mod - 2) % mod;
	rfor(i, m, 1) MOD(g[i] -= g[i - 1]);
}

signed main(){
	read(n), m = n * (n - 1) / 2;
	lfor(i, 1, n) read(p[i]), q[i] = Mod(1 - p[i]);
	lfor(i, 1, n){
		read(s[i]), a[i] = new int[s[i] + 1];
		lfor(j, 1, s[i]) read(a[i][j]), lnk[i][a[i][j]] = 1;
	}
	
	prep();
	get_coef();
	get_prob();
	
	lfor(i, 1, m) MOD(Ans += (LL) e[1][i] * g[i] % mod - mod);
	cout << Mod(Ans - 1) << endl;
	return 0;
}

标签:连通,cdot,题解,sum,岛屿,lfor,YZOJ50074,LL,mod
来源: https://www.cnblogs.com/Callis/p/16051494.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有