• [HNOI2004]树的计数


    [HNOI2004]树的计数

    一棵有n个有标号节点的树,设它第i个节点的度数为(v_i),询问这样的树的个数,1<=n<=150。

    显然为树的组合计数问题,与度数有关,考虑prefur序列,不难得知在prefur序列中,如果第i个节点的度数为(v_i),那么i将在序列中出现(v_i-1)次,所以答案就是

    [ans=frac{(n-2)!}{(v_1-1)!(v_2-1)!...(v_n-1)!} ]

    按照质因数分解的方式处理阶乘即可,注意判树是否成立。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    #define ll long long
    using namespace std;
    bool check[251];
    int d[151],prime[101],pt,tr[101];
    il ll pow(ll,ll);
    il void sieve(int);
    int main(){
        int n,i,j,k,tt(0);
        scanf("%d",&n);ll ans(1);
        if(n==1)return scanf("%d",&n),n?puts("0"):puts("1"),0;
        for(i=1;i<=n;++i){
            scanf("%d",&d[i]),tt+=d[i]-1;
            if(!d[i])return puts("0"),0;
        }if(tt!=n-2)return puts("0"),0;
        sieve(n);
        for(i=1;i<=pt;++i)for(j=n-2;j;j/=prime[i])tr[i]+=j/prime[i];
        for(i=1;i<=n;++i)
            for(j=1;j<=pt;++j)
                for(k=d[i]-1;k;k/=prime[j])
                    tr[j]-=k/prime[j];
        for(i=1;i<=n;++i)ans*=pow(prime[i],tr[i]);
        printf("%lld",ans);
        return 0;
    }
    il ll pow(ll x,ll y){
        ll ans(1);
        while(y){
            if(y&1)ans*=x;
            x*=x,y>>=1;
        }return ans;
    }
    il void sieve(int n){
        int i,j;check[1]|=true;
        for(i=2;i<=n;++i){
            if(!check[i])prime[++pt]=i;
            for(j=1;j<=pt&&i*prime[j]<=n;++j){
                check[prime[j]*i]|=true;
                if(!(i%prime[j]))break;
            }
        }
    }
    
  • 相关阅读:
    假期12
    假期11
    第十六章 IP子网的划分
    第十五章 链路聚合基本原理及其基本配置
    第十四章 交换机端口技术
    第十七章 nginx动静分离和rewrite重写
    第十六章 四层负载均衡
    第十五章 nginx七层负载均衡
    第十四章 nginx代理配置
    每日日报
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10853057.html
Copyright © 2020-2023  润新知