【组合数学】【prufer数列】【HNOI 2004】【bzoj 1211】树的计数

来源:互联网 发布:仙桃广电网络客服电话 编辑:程序博客网 时间:2024/05/17 06:03

1211: [HNOI2004]树的计数

Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1565  Solved: 512

Description

一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵。给定n,d1, d2, …, dn,编程需要输出满足d(vi)=di的树的个数。

Input

第一行是一个正整数n,表示树有n个结点。第二行有n个数,第i个数表示di,即树的第i个结点的度数。其中1<=n<=150,输入数据保证满足条件的树不超过10^17个。

Output

输出满足条件的树有多少棵。

Sample Input

4                     2 1 2 1

Sample Output

2

题解:

是明明的烦恼的弱化版。。做法大体相同,不用高精度真是开心。

Code:

#include<iostream>#include<cstdio>#include<cstdlib>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define N 210#define LL long longint n,s,d[N],su[N],ys[N];LL jc[30],ans;int in(){    int x=0; char ch=getchar();    while (ch<'0' || ch>'9') ch=getchar();    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();    return x;}void init(){    jc[0]=jc[1]=1;    for (int i=2; i<=25; i++) jc[i]=jc[i-1]*(LL)i;    for (int i=2; i<=N; i++){        bool f=true;        for (int j=2; j<=sqrt(i); j++)            if (!(i%j)){                f=false; break;            }        if (f) su[++su[0]]=i;    }}void fenjie(int x,int y){    for (int i=1; i<=su[0]; i++){        if (x<=1) return;        while (!(x%su[i]))            ys[i]+=y,x/=su[i];    }}int main(){    scanf("%d",&n);    if (n==1){        int x=in();        if (!x) ans=1;        else ans=0;        printf("%d\n",ans);        return 0;    }    for (int i=1; i<=n; i++){        d[i]=in();        if (!d[i]){            printf("0\n");            return 0;        }        d[i]--,s+=d[i];    }    if (s!=n-2){        printf("0\n");        return 0;    }    init(); ans=1;    if (n-2<=25) fenjie(jc[n-2],1);    for (int i=1; i<=n; i++)        fenjie(jc[d[i]],-1);    for (int i=1; i<=su[0]; i++)        while (ys[i]--) ans*=su[i];    printf("%d\n",ans);    return 0;}
1 0
原创粉丝点击