当前位置 博文首页 > 文章内容

    Solution -「CF 156D」Clues

    作者: 栏目:未分类 时间:2020-07-04 14:04:06

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    \(\mathcal{Description}\)

      link.
      给一个 \(n\) 个点 \(m\) 条边的无向图 \(G\)。设图上有 \(k\) 个连通块,求出添加 \(k-1\) 条边使得这些连通块全部连通的方案数。对给定的 \(p\) 取模。
      \(n,m\le10^5\)

    \(\mathcal{Solution}\)

      \(\text{Prufer}\) 序列,设第 \(i\) 个连通块(可能是单点)的度数为 \(d_i\),大小为 \(s_i\)。考虑连通块都是单点,方案数为:

    \[k-2\choose d_1-1,d_2-1,\cdots,d_k-1 \]

      即 \(k-2\) 个可重元素的排列数。接下来考虑连通块的大小,每个连通块都可以选出一个点来连边。所以方案数应乘上 \(s_i^{d_i}\)。那么方案数:

    \[{k-2\choose d_1-1,d_2-1,\cdots,d_k-1}\prod_{i=1}^ks_i^{d_i} \]

      枚举 \(t_i=d_i-1\)

    \[\sum_{t_i\ge0\land\sum t_i=k-2}{k-2\choose t_1,t_2,\cdots,t_k}\prod_{i=1}^ks_i^{t_i+1} \]

      发现有一个 \(k\) 元多项式 \(\sum_{i=1}^ks_i\)\(k-2\) 次方,提出来:

    \[\left(\sum_{i=1}^ks_i\right)^{k-2}\prod_{i=1}^ks_i \]

      显然 \(\sum_{i=1}^ks_i=n\),所以答案:

    \[n^{k-2}\prod_{i=1}^ks_i \]

    \(\mathcal{Code}\)

      为什么不直接打并查集啊喂。

    #include <cstdio>
    #include <vector>
    
    const int MAXN = 1e5, MAXM = 1e5;
    int n, m, p, ecnt, head[MAXN + 5];
    std::vector<int> siz;
    bool vis[MAXN + 5];
    
    struct Edge { int to, nxt; } graph[MAXM * 2 + 5];
    
    inline void link ( const int s, const int t ) { graph[++ ecnt] = { t, head[s] }, head[s] = ecnt; }
    
    inline int qkpow ( int a, int b ) {
    	int ret = 1;
    	for ( ; b; a = 1ll * a * a % p, b >>= 1 ) ret = 1ll * ret * ( b & 1 ? a : 1 ) % p;
    	return ret;
    }
    
    inline int DFS ( const int u ) {
    	if ( vis[u] ) return 0;
    	int ret = vis[u] = true;
    	for ( int i = head[u]; i; i = graph[i].nxt ) ret += DFS ( graph[i].to );
    	return ret;
    }
    
    int main () {
    	scanf ( "%d %d %d", &n, &m, &p );
    	if ( p == 1 ) return puts ( "0" ), 0;
    	for ( int i = 1, u, v; i <= m; ++ i ) {
    		scanf ( "%d %d", &u, &v );
    		link ( u, v ), link ( v, u );
    	}
    	int ans = 1;
    	for ( int i = 1, t; i <= n; ++ i ) {
    		if ( ! vis[i] ) {
    			siz.push_back ( t = DFS ( i ) );
    			ans = 1ll * ans * t % p;
    		}
    	}
    	if ( siz.size () == 1 ) return puts ( "1" ), 0;
    	ans = 1ll * ans * qkpow ( n, siz.size () - 2 ) % p;
    	printf ( "%d\n", ans );
    	return 0;
    }