• 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);
            }
        }
    }
    
  • 相关阅读:
    web前端学习笔记(CSS盒子的定位)
    web前端学习笔记(CSS盒子的浮动)
    数百篇「原创」文章,助你完成技术「体系化」
    linux quota磁盘限额,引发的rename系统调用 errno:18
    dnsperf
    stop容器,把信号量传给java进程,优雅退出
    JNA 调用操作系统函数 和 系统调用
    自顶向下深入分析Netty(五)--Future
    来测试下你的Java编程能力
    Netty笔记
  • 原文地址:https://www.cnblogs.com/whitelily/p/13397005.html
Copyright © 2020-2023  润新知