• 2020年HDU多校第三场 1005 Little W and Contest(并查集与数学)


    2020年HDU多校第三场 1005 Little W and Contest(并查集与数学)

    题意:给n个人与每个的能力值(2或1),组一个3人的队能力和至少5以上,同在一个集合的人不能组队,最开始每个人都在自己的集合,询问n-1次,每次将任意两人所在的集合合并之后输出多少种组队方案。

    题解:先撇开5以上不说,解决3人组队的问题,最开始就一个comb(n,3),主要是合并以后怎么求,我们可以考虑合并以后对原结果的影响,设x集合的人,与y集合的人合并,那么原本x的人,与y的人的组合方案我就得去掉,去掉的值为x * y * (n-x-y),即x中取一人,y中取一人,x,y之外取一个人的方案数,那么为什么不用去除x取一人,y中取二人的方案呢,因为在y之前合并的时候已经去除的此方案数,现在引入题目为5以上的要求,枚举一下就好了,221,222,122,212;

    #include<iostream>
    using namespace std;
    #define ll long long
    ll t,lin,n,fa[100007],sum2,sum1,ans,u,v,res;
    struct madoka{
        ll one;
        ll two;
        ll siz;
    }ma[100007];
    const long long mod = 1e9+7;
    long long fac[2000006];
    long long qpow(long long x, long long n) {
        long long res = 1;
        for (; n; n >>= 1, x = x * x % mod)
            if (n & 1) res = res * x % mod;
        return res;
    }
    long long inv(long long a) {
        return qpow(a, mod-2)%mod;
    }
    void solve() {
        fac[0] = 1;
        for(int i = 1;i <= 2000006; i++) {
            fac[i] = (fac[i-1]*i)%mod;
        }
    }
    long long comb(long long n, long long k) {
        if(k > n) return 0;
        return (fac[n]*inv(fac[k])%mod * inv(fac[n-k])%mod);
    }
    
    ll fin(int p){
        if(p==fa[p])return p;
        else{
            return fa[p]=fin(fa[p]);
        }
    }
    void go(int f1,int f2){
        ll o1=ma[f1].one;
        ll o2=ma[f2].one;
        ll t1=ma[f1].two;
        ll t2=ma[f2].two;
        res=(res+comb(t1,1)*comb(t2,1)%mod*comb(sum2-t1-t2,1))%mod;
        res=(res+comb(t1,1)*comb(t2,1)%mod*comb(sum1-o1-o2,1))%mod;
        res=(res+comb(o1,1)*comb(t2,1)%mod*comb(sum2-t1-t2,1))%mod;
        res=(res+comb(t1,1)*comb(o2,1)%mod*comb(sum2-t1-t2,1))%mod;
        ma[f1].one+=ma[f2].one;
        ma[f1].two+=ma[f2].two;
        ma[f1].siz+=ma[f2].siz;
        fa[f2]=f1;
    }
    void init(){
        for(int i=1;i<=n;i++){
            fa[i]=i;
            ma[i].one=0;
            ma[i].two=0;
            ma[i].siz=0;
        }
        sum1=0;
        sum2=0;
        ans=0;
        res=0;
    }
    int main(){
        solve();
        scanf("%lld",&t);
        while(t--){
            scanf("%lld",&n);
            init();
            for(int i=1;i<=n;i++){
                scanf("%lld",&lin);
                if(lin==1){
                    ma[i].one++;
                    sum1++;
                }
                else {
                    ma[i].two++;
                    sum2++;
                }
                ma[i].siz=1;
            }
            ans=(comb(sum1,1)*comb(sum2,2)%mod+comb(sum2,3))%mod;
            printf("%lld
    ",ans);
            for(int i=1;i<n;i++){
                scanf("%lld%lld",&u,&v);
                int f1=fin(u),f2=fin(v);
                go(f1,f2);
                printf("%lld
    ",(ans-res+mod)%mod);
            }
        }
    }
    
  • 相关阅读:
    Sexy Beach PR 汉化补丁+入门教程
    [Unity3D]Script 脚本全部编译器属性具体解释
    图论--最小生成树和最短路1
    软件设计师之路总结~引——时间的温度
    BZOJ1441: Min
    BZOJ1602: [Usaco2008 Oct]牧场行走
    BZOJ1600: [Usaco2008 Oct]建造栅栏
    BZOJ1599: [Usaco2008 Oct]笨重的石子
    BZOJ1601: [Usaco2008 Oct]灌水
    BZOJ1058: [ZJOI2007]报表统计
  • 原文地址:https://www.cnblogs.com/whitelily/p/13397005.html
Copyright © 2020-2023  润新知