【bzoj1284】【HNOI2004】【树的计数】【组合数学+prufer数列】

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
题解:首先需要知道有个东西叫prufer数列。然后可以发现一个节点在prufer数列中出现的次数是这个节点的度数减一。这样我们就知道这个数列中有哪些数了。因为一个prufer数列唯一对应一颗树。然后问题就变成了求有多少种prufer数列。又因为我们知道了元素种类与出现次数。于是问题就变成了求一个有重复元素的全排列。
因为n最大有150.所以分解一下质因数就好了。
注意一开始要先判断是否有解。即把所有点的度数减一然后加起来,如果不等于n-2就无解。
#include<cstdio>
using namespace std;
int n,tot,p[2][151],x;
long long ans(1);
void cal(int x,int k)
{   
  for (int i=2;;i++)
     {
        if (x%i==0) while (x%i==0) {p[k][i]++;x/=i;}
        if (x==1) break;
     }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) 
     {
       scanf("%d",&x);
       if (x>2) 
        {
          for (int j=1;j<=x-1;j++) cal(j,1);
        }
       if (x>1) tot+=x-1; 
     }
    if (n==1) {printf("%d",!x);return 0;}
    if(tot!=n-2) {printf("0");return 0;} 
    for (int i=2;i<=tot;i++) cal(i,0);
    for (int i=1;i<=150;i++)
     if (p[0][i]-p[1][i]>0)
       for (int j=1;j<=p[0][i]-p[1][i];j++)
         ans*=(long long)i;
    printf("%lld",ans);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值