zoukankan      html  css  js  c++  java
  • 2020 Multi-University Training Contest 3 Little W and Contest (多项式计数+并查集 or 排列组合)

    题面

    There are n members in our ACM club. Little W wants to select three persons from our club to form a new team taking part in provincial ACM contests, as it is known by all of us that any ACM contest requires a normal team to have three members.

    Little W has divided our club members into two role groups. The first group contains only readers who dedicate themselves to reading problems during contests, though sometimes they may also prepare drinking and food for the team. For the sake of measurement, we define the power of a reader as 1. The second part contains only coders who code and test programs all the time, and similarly, we define the power of a coder as 2.

    Little W thinks it will be a tremendous disaster when a team has two readers because in that case, the total power of this team is less than 5 and thus it has a high risk to fail the contest. To avoid that, Little W thinks a new team must have at least two coders.

    Additionally, Little W defines the relationship between club members with transitivity. That is, for every three members A, B, and C, if A is familiar with B, and B is familiar with C, then A will be familiar with C through B instantly. Based on the definition, it is forbidden for the team to have any two members familiar with each other.

    At first, no member of our club is familiar with any other, and then Little W will repeatedly make an introduction between two members who are currently strangers to each other until each member is familiar with all the others. During this process, there will be exactly (n−1) introductions.

    Now, for i=1,2,…,n, Little W wants you to count the combinations of three club members that can form a new team after the first (i−1) introductions have been made. However, the numbers of combinations may be quite gigantic, so you just need to report each number in modulo (109+7).

    Input
    There are several test cases.

    The first line contains an integer T (1≤T≤10), denoting the number of test cases. Then follow all the test cases.

    For each test case, the first line contains an integer n (1≤n≤105), denoting the number of members in this club.

    The second line contains n integers consisting of only 1 and 2, where the i-th integer represents the power of the i-th member.

    The next (n−1) lines describe all introductions in chronological order of occurrence, where each line contains two integers u and v (1≤u,v≤n,u≠v), representing an introduction between the u-th member and the v-th member, who are currently strangers to each other.

    It is guaranteed that the sum of n is no larger than 106.

    Output
    For each test case, output n lines, where the i-th line contains an integer, denoting the number of combinations of three club members, in modulo (109+7), that can form a new team after the first (i−1) introductions have been made.

    Sample Input
    1
    5
    2 2 2 1 1
    4 5
    1 4
    2 1
    3 2

    Sample Output
    7
    7
    3
    0
    0

    题意

    给定一张图,每个点带有权值2或者1,现在我们要去合并集合,使得最后组队成为221或者222的形式,问每次操作后的配对数。看上去就是一个排列组合问题,那么我们可以先把所以可能的数列出来,然后每次合并减去浪费的组合数,然后对于组合计数的统计的话我们有一种更加方便和模板化的东西叫多项式计数,我们可以把最后的方案数看做是一个固定多项式的常系数,这个多项式式由题目所确定的,这里我们可以使用可撤销背包去维护这个系数。顺便贴一下队友写的排列组合代码...

    代码实现

    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #include<set>
    #include<map>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    using namespace std;
    #define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
    #define per(i,n,a) for (int i=n;i>=a;i--)
    #define MT(x,i) memset(x,i,sizeof(x) )
    #define rev(i,start,end) for (int i=0;i<end;i++)
    #define inf 0x3f3f3f3f
    #define mp(x,y) make_pair(x,y)
    #define lowbit(x) (x&-x)
    #define MOD 1000000007
    #define exp 1e-8
    #define N 1000005 
    #define fi first 
    #define se second
    #define pb push_back
    typedef long long ll;
    typedef pair<int ,int> PII;
    ll qpow (ll a,ll n) {ll res=1; while (n){if(n&1) res=res*a;a=a*a; n>>=1;} return res;} 
    ll gcd (ll a,ll b) {return b?gcd (b,a%b):a; }
    const int maxn=100010;
    const int mod=1e9+7;
    int f[maxn],a[maxn],b[maxn];
    struct node {
        ll dp[4][7];
        void init () {
            rep (i,0,3)  
             rep (j,0,6) {
                 dp[i][j]=0;
             }
             dp[0][0]=1;
        }
        void mul (ll a,ll b) {
          per (i,3,1) {
             per (j,6,1) {
                 dp[i][j]+=dp[i-1][j-1]*a%mod;
                 if (j>1) dp[i][j]+=dp[i-1][j-2]*b%mod;
                 dp[i][j]%=mod;
             }
          }
        }
        void div (ll a,ll b) {
            rep (i,1,3) {
                rep (j,1,6) {
                    dp[i][j]-=dp[i-1][j-1]*a%mod;
                    if (j>1) dp[i][j]-=dp[i-1][j-2]*b%mod;
                    dp[i][j]=(dp[i][j]%mod+mod)%mod;
                }
            }
        }
        ll get () {
            return (dp[3][5]+dp[3][6])%mod;
        }
    
    }ans;
    
    inline int find (int x) {
        if (f[x]==x) return x;
        else return f[x]=find (f[x]);
    }
    
    inline void merge (int x,int y) {
        x=find (x);
        y=find (y);
        if (x!=y) {
            f[x]=y;
            a[y]+=a[x];
            b[y]+=b[x];
        }
    }
    
    inline void solve () {
       ans.init ();
       int n;
       cin>>n;
       rep (i,1,n) {
           f[i]=i;
           a[i]=b[i]=0;
           int x;
           cin>>x;
           if (x==2) {
               b[i]++;
           }
           else a[i]++;
           ans.mul (a[i],b[i]);
       }
        printf ("%lld
    ",ans.get ());
        rep (i,1,n) {
            int x,y;
            cin>>x>>y;
            x=find (x);
            y=find (y);
            ans.div (a[x],b[x]);
            ans.div (a[y],b[y]);
            merge (x,y);
            ans.mul (a[y],b[y]);
            printf ("%lld
    ",ans.get ());
        }
    }
    
    int main () {
        int t;
        cin>>t;
        while (t--) {
            solve ();
        }
        return 0;
    }
    
    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    #include<math.h>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    #include<list>
    #include<algorithm>
    #include<iomanip>
    using namespace std;
    typedef long long ll;
    #define SIS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    #define endl '
    '
    #define mod MOD
    
    const int MOD = 1e9 + 7;
    const int MAXN = 1e5+5;
    int p[MAXN];
    int s[MAXN];
    int a1[MAXN],a2[MAXN];
    int n,A1,A2;
    
    ll AA(ll n, ll m){   //排列数  
    if(m > n)return 0;  
        ll re = 1,i;  
        for(i = 1; i <= m; ++i){  
            re *= n-i+1;  
        }  
        return re;  
    }  
      
    ll CC(ll n, ll m){   //组合数  
        if(m > n)return 0;  
        ll re = 1, i;  
        if(m>(n-m))m = n - m;  
        for(i = 1; i <= m; ++i){  
            re = re*(i+(n-m))/i;  
        }  
        return re;  
    } 
    
    ll pw(ll x,ll y,int MOD) {
        x%=MOD;
        ll res=1;
        while(y) {
            if(y&1) res=res*x%MOD;
            x=x*x%MOD;
            y>>=1;
        }
        return res;
    }
    
    ll inv(ll a,ll p){
        return pw(a,p-2,mod);
    }
    
    ll C(ll n,ll m) {
        if(m==2&&n>1) return n*(n-1)%mod*inv(2,mod)%mod; 
        if(m==3&&n>2) return n*(n-1)%mod*(n-2)%mod*inv(6,mod)%mod;
        return 0;
    }
    
    int find_set(int x){ 
        int r=x;
        while(s[r]!=r)r=s[r];
        int i=x,j;
        while(i!=r){
            j=s[i];
            s[i]=r;
            i=j;
        }
        return r;
    }
    void merge_set(int x,int y){
        x=find_set(x);
        y=find_set(y);
        if(x!=y)s[x] = y; 
    }
    
    ll ff(ll a1,ll a2) {
        return (C(a2,3)+C(a2,2)*a1+C(a2,2)*(n-a1-a2)%mod+a1*a2%mod*(A2-a2)%mod)%mod;
    }
    void init(){
        for(int i=1;i<=MAXN;i++) {
                s[i]=i;
            }
    }
    int x,y,cc;
    int main() {
        scanf("%d",&cc);
        while(cc--) {
            scanf("%d",&n);
            memset(a1,0,sizeof(a1));
            memset(a2,0,sizeof(a2));
            init();
            A1=0;A2=0;
            for(int i=1;i<=n;i++) {
                scanf("%d",&p[i]);
                if(p[i]==1) {
                    A1++;a1[i]++; //X
                } 
                if(p[i]==2) {
                    A2++;a2[i]++;  //Y
                }
            }
            ll ans=0;
            ans=(C(A2,3)+C(A2,2)*A1%mod)%mod;
            printf("%lld
    ",ans);
            
            int nnn = n-1;
            while(nnn--) {
               
                scanf("%d%d",&x,&y);
                int rx = find_set(x);
                int ry = find_set(y);
                if(rx!=ry) {
                    ans=(ans+ff(a1[rx],a2[rx])+ff(a1[ry],a2[ry]))%mod;
                    a1[rx]+=a1[ry];
                    a2[rx]+=a2[ry];
                    s[ry]=rx;
                    ans=((ans-ff(a1[rx],a2[rx]))%mod+mod)%mod;
                }
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Mongodb常用操作(转载)
    java中对象转换工具类,很好用
    IDEA中配置tomcat出现乱码的解决
    小山博客--面试题答案
    Redis简单配置和使用
    线程的控制和线程池
    进程与线程详细解释
    Quartz .Net(定时框架):
    C#面向对象几组关键字的详解(this,base,dynamic,var,const,readonly,is,as)
    C#设计模式--抽象工厂模式(创建型模式)
  • 原文地址:https://www.cnblogs.com/hhlya/p/13405592.html
Copyright © 2011-2022 走看看