【CF913F】Strongly Connected Tournament

题面

洛谷

题解

\(f_i\)表示大小为\(i\)的竞赛图的场数期望,\(g_i\)表示形成大小为\(i\)\(SCC\)的概率,\(h_{i,j}\)\(i\)个人打比赛,其中\(j\)个人被剩下\(i-j\)个人打爆的概率。

枚举最后一个\(SCC\)的大小,有

\[f_i=\sum_{j=1}^i g_jh_{i,j}(f_{i-j}+f_i+{j\choose 2}+j(i-j)) \]

发现这个\(f\)会转移到自身,解一下方程就行了,这里不再赘述。

现在考虑\(g_i\)怎么求,考虑构成\(SCC\)的条件,就是对于一个集合\(S\),不能存在一个集合\(T\),集合\(T\)打爆集合\(\complement_S T\),容斥一下得

\[g_i=1-\sum_{j=1}^{i-1}g_j\times h_{i,j} \]

最后考虑怎么求\(h\),相当于新加入一个点,他可以放到赢或输的集合中,转移类似于杨辉三角:

\[h_{i,j}=h_{i-1,j-1}\times p^{i-j}+h_{i-1,j}\times (1-p)^{j} \]

然后就可以根据推好的式子就可以算出来答案了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm> 
using namespace std; 
const int Mod = 998244353; 
const int MAX_N = 2e3 + 5; 
int fpow(int x, int y) {
	int res = 1; 
	while (y) {
		if (y & 1) res = 1ll * res * x % Mod; 
		x = 1ll * x * x % Mod; 
		y >>= 1; 
	} 
	return res; 
} 
int N, p, p1[MAX_N], p2[MAX_N]; 
int f[MAX_N], g[MAX_N], h[MAX_N][MAX_N]; 
int main () { 
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin); 
#endif 
	cin >> N; 
	int a, b; cin >> a >> b; 
	p = 1ll * a * fpow(b, Mod - 2) % Mod; 
	p1[0] = p2[0] = 1; 
	for (int i = 1; i <= N; i++) {
		p1[i] = 1ll * p1[i - 1] * p % Mod; 
		p2[i] = 1ll * p2[i - 1] * (Mod + 1 - p) % Mod; 
	} 
	for (int i = 0; i <= N; i++) 
		for (int j = h[i][0] = 1; j <= i; j++) 
			h[i][j] = (1ll * h[i - 1][j - 1] * p1[i - j] + 1ll * h[i - 1][j] * p2[j]) % Mod; 
	for (int i = 1; i <= N; i++) 
		for (int j = g[i] = 1; j < i; j++) 
			g[i] = (g[i] - 1ll * g[j] * h[i][j] % Mod + Mod) % Mod; 
	for (int i = 2; i <= N; i++) { 
		int C = i * (i - 1) / 2; 
		f[i] = 1ll * g[i] * h[i][i] % Mod * C % Mod; 
		for (int j = 1; j < i; j++) { 
			C = j * (j - 1) / 2; 
			f[i] = (f[i] + 1ll * g[j] * h[i][j] % Mod * (1ll * f[i - j] + f[j] + C + (i - j) * j)) % Mod; 
		} 
		f[i] = 1ll * f[i] * fpow(1 - 1ll * g[i] * h[i][i] % Mod + Mod, Mod - 2) % Mod; 
	} 
	printf("%d\n", f[N]); 
    return 0; 
} 
posted @ 2020-01-15 21:26  heyujun  阅读(234)  评论(1编辑  收藏  举报