CF913F

CF913F

给定 (n)(p),现在有一张 (n) 个点的完全无向图。并按照此规则:

  1. 先给每条边随机定向,以 (p) 的概率从编号小的指向大的,以 (1-p) 的概率从大的指向小的,此时的贡献为被定向的边的边数。
  2. 然后缩点,这样会剩余一张形如 (A_1 o A_2 o A_3 o ... o A_k) 的图。
  3. 对于每个 (i=1,2...k) 如果 (|A_i| e 1),那么对这个连通块的子图重新执行这个流程。

求期望贡献和。

(nle 2000)

Solution

注意到点是等价的,同时递归处理的时候存在很明显的子问题性,那么考虑递推,设 (f_i) 表示 (i) 个点的时候的答案,那么 (f_1=0)

枚举 Top 序最高的连通块的大小 (j),那么设 (g_j) 表示 (j) 个点的完全图生成的所有强连通图的概率和。

此时贡献为:

[f_i=inom{i}{2}+sum_{j} g_j imes (j o other) imes (f_j+h_{i-j}) ]

其中 (h) 表示大小为 (i-j) 的图,已经定了边的期望次数(等价于拿掉了 (inom{i}{2}))后的式子。

考虑 (j o other) 如何计算,不难发现我们只关注那些点被选入了 Top 序最高的强连通块中。

假设被选入的点集为 (S),此时贡献为 (prod_{xin S} (prod_{i ot in S,i<x}pprod_{i ot in S,i>x}(1-p))),设为 (w(S)),我们想求的即 (sum_{|S|=j} w(S))

(sum_{|S|=j}w(S)) 的处理可以通过 dp 处理,设 (dp_{i,j}) 表示当前考虑到编号 (i),当前的集合 (S) 大小为 (j),那么考虑加入一个 (i+1),此时转移为:

  1. (dp_{i+1,j}leftarrow dp_{i,j} imes p^j)
  2. (dp_{i+1,j+1}leftarrow dp_{i,j} imes (1-p)^{i-j})

我们可以 (mathcal O(n^2)) 的预处理 (f) 数组。

考虑大小为 (j) 的完全图生成的强连通图的概率和 ((g_j))

我们考虑计算所有可能的图减去非强连通图的方案数。

我们考虑枚举 Top 最高的点的数量 (k),此时对答案的贡献为 (-(k o other) imes g_{k})

不难发现此处需要用到的 ((k o other)) 和之前要用的类似,仅为 (dp) 数组在 (i) 较小的情况!(即点数不为 (n) 的情况)

那么我们可以 (mathcal O(n^2)) 的递推 (g_k),然后可以 (mathcal O(n^2)) 的递推 (f)(h) 即可。

(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
#define int long long 
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 = 3000 + 5 ; 
const int P = 998244353 ; 
int fpow(int x, int k) {
	int ans = 1, base = x ;
	while(k) {
		if(k & 1) ans = 1ll * ans * base % P ;
		base = 1ll * base * base % P, k >>= 1 ;
	} return ans ;
}
int n, p, fv1[N], fv2[N], dp[N][N], h[N], g[N], f[N] ; 
void inc(int &x, int y) { x += y, x %= P ; }
signed main()
{
	n = gi() ; int a = gi(), b = gi() ;
	p = a * fpow(b, P - 2) % P, fv1[0] = fv2[0] = 1 ;
	rep( i, 1, n ) fv1[i] = fv1[i - 1] * p % P ;
	rep( i, 1, n ) fv2[i] = fv2[i - 1] * (1 - p + P) % P ; 
	dp[0][0] = 1 ;
	for(int i = 0; i < n; ++ i) {
		rep( j, 0, i ) 
			inc( dp[i + 1][j], dp[i][j] * fv1[j] % P ),
			inc( dp[i + 1][j + 1], dp[i][j] * fv2[i - j] % P ) ;
	}
	g[1] = 1, h[1] = f[1] = 0 ; 
	rep( i, 2, n ) {
		g[i] = 1 ; 
		for(re int k = 1; k < i; ++ k) 
			inc(g[i], P - g[k] * dp[i][k] % P) ; 
		int k = 1 - g[i] + P, c = (i * (i - 1) / 2) ; 
		k %= P, k = fpow(k, P - 2) ; 
		for(re int j = 1; j < i; ++ j)
		inc(c, g[j] * dp[i][j] % P * (f[j] + h[i - j]) % P) ; 
		f[i] = c * k % P ;
		for(re int j = 1; j <= i; ++ j)
		inc(h[i], g[j] * dp[i][j] % P * (f[j] + h[i - j]) % P) ; 
	}
	printf("%lld
", f[n] ) ; 
	return 0 ;
}
原文地址:https://www.cnblogs.com/Soulist/p/13724629.html