zoukankan      html  css  js  c++  java
  • 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 ;
    }
    
  • 相关阅读:
    个人作业——软件工程实践总结作业
    用户调查报告
    β总结
    凡事预则立
    学习进度条
    作业八——单元测试练习(个人练习)
    作业七——“南通大学教务管理系统微信公众号” 用户体验分析
    作业六——团队作业(学生成绩录入系统设计与实现)
    作业5——需求分析(学生成绩录入系统)
    作业4.2:结对项目—— 词频统计(第二阶段)
  • 原文地址:https://www.cnblogs.com/Soulist/p/13724629.html
Copyright © 2011-2022 走看看