Codeforces Round #110 (Div. 1) D Clues

Posted n-psong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #110 (Div. 1) D Clues相关的知识,希望对你有一定的参考价值。

题目链接:Clues

题意:一个无向图,图中有很多联通块,现在要添加最少数目的边,使得整个图都联通,问有多少种加边的方法。

题解:对于联通块,直接并查集处理计数即可。并令联通块的数目为 t ,总点数为 n。

   剩下的内容需要先了解 prufer 序列:https://www.cnblogs.com/dirge/p/5503289.html

   因此可构造序列为 n^(t-2) 种。在构造 prufer 后还需要进行删块,由于一条边可能连进这个联通块内的任意点,所以对于删除的块 i,需要乘上 num[i]。最后剩下的两个块之间相互连边的数目也是块数相乘。所以最后的答案就是:nt-2×∏num[i]。需要特殊处理的时只有一个块时候的情况。

#include <bits/stdc++.h>
using namespace std;

int n,m,k;
int f[100005],num[100005];
int find(int x){
    return f[x]==x?x:f[x]=find(f[x]);
}
void merge(int x,int y){
    int fx=find(x),fy=find(y);
    if(fx==fy) return;
    num[fx]+=num[fy];
    f[fy]=fx;
}
void init(){
    for(int i=1;i<=n;i++) f[i]=i,num[i]=1;
}

int vis[100005],block[100005],cnt;
int pow_mod(int a,int n){
    long long res=1,t=a;
    while(n){
        if(n&1) res=(res*t)%k;
        t=(t*t)%k;
        n/=2;
    }
    return res;
}
int solve(){
    if(cnt==1) return 1%k;

    long long res=pow_mod(n,cnt-2);
    for(int i=1;i<=cnt;i++){
        res=(res*block[i])%k;
    }
    return res;
}

int main(){
    scanf("%d%d%d",&n,&m,&k);
    init();
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        merge(u,v);
    }
    for(int i=1;i<=n;i++){
        int fx=find(i);
        if(vis[fx]) continue;
        vis[fx]=1;
        block[++cnt]=num[fx];
    }
    printf("%d
",solve());

    return 0;
}

 

以上是关于Codeforces Round #110 (Div. 1) D Clues的主要内容,如果未能解决你的问题,请参考以下文章

Educational Codeforces Round 110 (Rated for Div. 2)Codeforces-1535

Educational Codeforces Round 110 (Rated for Div. 2)Codeforces-1535

Codeforces Round #110 (Div. 1) D Clues

Codeforces Round #110 (Div. 1) C Cipher

Educational Codeforces Round 110 div.2 A~F题解

Educational Codeforces Round 110 div.2 A~F题解