zoukankan      html  css  js  c++  java
  • 2019牛客多校第⑨场E All men are brothers(并查集+组合数学)

    原题:https://ac.nowcoder.com/acm/contest/889/E

    思路:

    做并查集,维护每个集合大小,初始化操作前的总方案数,每次合并两个集合时减少的数量=合并的两个集合大小相乘, 再乘以从其他集合中选出2个不在一个集合内的方案数。

    从其他集合中选出2个不在一个集合内的方案数=任选2个的方案数-来自同一个集合的方案数

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    const ll maxn=1e5+5;
    ll fa[maxn],cnt[maxn];
    ll n,m,tot;
    ll find(ll x){
    	return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    int main(){
    	cin>>n>>m;
    	for(ll i=1;i<=n;i++){
    		fa[i]=i;
    		cnt[i]=1;
    	}
    	tot=n;
    	ll x,y;
    	ll res=n*(n-1)*(n-2)/2/3;
    	if(res%4==0){
    		res=res/4*(n-3);
    	}
    	else res=(n-3)/4*res;
    	ll del=0;//计算所有>=2的集合中选两个的方案数之和 
    	printf("%lld
    ",res);
    	for(ll i=1;i<=m;i++){
    		scanf("%d%d",&x,&y);
    		if(find(x)!=find(y)){
    			if(tot<=4) res=0;
    			else{
    				ll s1=cnt[fa[x]],s2=cnt[fa[y]];
    				ll temp=(n-s1-s2)*(n-s1-s2-1)/2; //C(tot-2,2);
    				ll temp2=del;
    				temp2-=s1*(s1-1)/2+s2*(s2-1)/2;
    				del-=s1*(s1-1)/2+s2*(s2-1)/2;//先减,等一会加上合并之后的
    				res-=s1*s2*(temp-temp2);
    				ll s3=s1+s2;
    				del+=s3*(s3-1)/2;
    				ll fx=fa[x],fy=fa[y];
    				fa[fx]=fy;
    				cnt[fy]+=cnt[fx];
    			}
    			tot--;
    		}
    		printf("%lld
    ",res);
    	}
    }
    
  • 相关阅读:
    关于ios6.0和5.0的横竖屏支持方法
    windows环境下搭建vue+webpack的开发环境
    诗歌类网址
    【第1阶段—GIS网址清单】其它杂项
    android内存指标
    Rownum与Order by
    使用反射复制一个JavaBean的对象
    catalog
    oralce中rownum理解
    BlockingQueue
  • 原文地址:https://www.cnblogs.com/ucprer/p/11359816.html
Copyright © 2011-2022 走看看