zoukankan      html  css  js  c++  java
  • 【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+{jchoose 2}+j(i-j)) ]

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

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

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

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

    [h_{i,j}=h_{i-1,j-1} imes p^{i-j}+h_{i-1,j} imes (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
    ", f[N]); 
        return 0; 
    } 
    
  • 相关阅读:
    Linux和Docker常用命令
    学习docker on windows (1): 为什么要使用docker
    使用xUnit为.net core程序进行单元测试(4)
    使用xUnit为.net core程序进行单元测试(3)
    高效地使用搜索引擎
    充分条件和必要条件
    上海全球“编程一小时”活动记
    C#.NET股票历史数据采集,【附18年历史数据和源代码】
    R学习笔记 ---- 系列文章
    平方根的原理
  • 原文地址:https://www.cnblogs.com/heyujun/p/12198860.html
Copyright © 2011-2022 走看看