组合数学 + 并查集 - Little W and Contest - HDU 6795

在这里插入图片描述
题意:

就是有两类人,第一类人的能量值为1,第二类人的能量值为2,你要从中选择三个人且加起来的能量值不能小于5而且这三个人必须是互不相识的。
还需满足的要求:
1.开始时他们互不相识,认识是有传递性的 比如A认识B B认识C 那么A也认识C
2.每次输入两个整数,输入之后代表这两个人认识了,输入n-1次,使得最后每个人都互相认识。

样例输入:

1
5
2 2 2 1 1
4 5
1 4
2 1
3 2

样例输出:

7
7
3
0
0

分析:

把有关系的放在一个集合通过并查集,并且用两个数组分别记录每一个集合中能量值为2和能量值为1的人数。

代码

在这里插入代码片
#include <bits/stdc++.h>

#define ll long long
using namespace std;

int a[100001];
int vis[100001];
int p2[100001]; //该节点的集合下为2的个数
int p1[100001];//该节点的集合下为1的个数
int fa[100001]; //相互之间具有关系的人放在一起
int cnt1=0,cnt2=0;
ll mod=1e9+7;
int fac(int x){

    return fa[x]==x?x:fa[x]=fac(fa[x]);
}

int main()
{
    ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);
    int t;
    cin>>t;
    while(t--){
       int n;
       cin>>n;
       cnt1=0,cnt2=0;
       for (int i=1;i<=n;i++){
        cin>>a[i];
        if(a[i]==1){
            p1[i]=1;
            p2[i]=0;
            fa[i]=i;
            cnt1++;
        }
        else{
          p1[i]=0;
            p2[i]=1;
            fa[i]=i;
            cnt2++;
        }
       }
       ll ans=(cnt1*cnt2*(cnt2-1)/2%mod+cnt2*(cnt2-1)*(cnt2-2)/6%mod)%mod;
       // C cnt2中取3  cnt2中取2cnt1 中取1
       cout<<ans<<endl;
       for (int i=0;i<n-1;i++){
        //每次在上一次的ans上减去先增加的关系中不满足的情况
        //增加新关系之后 相对于上一次减去增加的新关系中不符合要求的
        //考虑再新增加一个关系x y之后,相对于上一次的关系,
      //  分为三部分,一部分为fa[x],fa[y],还有一部分就是剩余的
    //    相对于上一次的所有情况中,增加这个关系之后,不满足的选择有四种,
       // 从fa[x] 集合中选择一个 fx[y]集合中选择一个 剩余的集合中选择一个
       // 分别选择的能力值为2 2 1 
       //      2 1 2  1 2 2  2 2 2
        //如果你认为从只从fa[x]或fa[y]集合中选择三个满足能力值大于5的三个人也为
       // 不满足的情况,那这个认为是错误的,因为fa[x]这个集合里面的元素都是有关系的,
        //而在上一次求得的ans中没有加入这种情况,只是加入新增加的四种情况。
          int x,y;
          cin>>x>>y;
          int fx=fac(x);
          int fy=fac(y);
          ll k=0; //k 为不符合条件的那些人
     
           k= (ll)p2[fx]*p2[fy]*(cnt1-p1[fx]-p1[fy])%mod;// 2 2 1
           k=(k+(ll)p2[fx]*p1[fy]*(cnt2-p2[fx]-p2[fy]))%mod; // 2 1 2
           k=(k+(ll)p1[fx]*p2[fy]*(cnt2-p2[fx]-p2[fy]))%mod; // 1 2 2
           k=(k+(ll)p2[fx]*p2[fy]*(cnt2-p2[fx]-p2[fy]))%mod; // 2 2 2
           ans=(ans-k+mod)%mod;
           cout<<ans<<endl;
       fa[fy]=fx;
       p1[fx]+=p1[fy];
       p2[fx]+=p2[fy];
       p1[fy]=0,p2[fy]=0;
       }
    }
}


猜你喜欢

转载自blog.csdn.net/weixin_44711328/article/details/107727446