zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    CF238B Boring Partition
    CF1424G Years
    CF995D Game
    CF468C Hack it!
    CF1417A Copy-paste
    CF1417B Two Arrays
    CF849B Tell Your World
    [洛谷P3389][模板]高斯消元法
    CF1225D
    P6687
  • 原文地址:https://www.cnblogs.com/N-Psong/p/10281597.html
Copyright © 2011-2022 走看看