【刷题】BZOJ 1211 [HNOI2004]树的计数

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

Solution

水一道题
prufer序上每个点出现的次数等于它的度数-1
那么这道题就转化成了一个序列,要有一些位置放某一个数,另一些位置放某一个数,另一些位置……
就是个组合数裸题了
最后其实有个结论式子,就是题目的条件,最后结果是 \(\frac{(n-2)!}{(d_1-1)!(d_2-1)!...(d_n-1)!}\)
然后这道题卡精度,要么写高精,要么如下程序里写的分解质因数计算,最后相乘的答案

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=150+10;
int n,d[MAXN],cnt[MAXN];
ll ans;
std::vector<int> V[MAXN];
template<typename T> inline void read(T &x)
{
	T data=0,w=1;
	char ch=0;
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
	x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
	if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void init()
{
	for(register int x=2;x<=150;++x)
	{
		int i=2,now=x;
		while(now>1)
		{
			while(now%i==0)V[x].push_back(i),now/=i;
			++i;
		}
	}
}
inline ll qexp(ll a,ll b)
{
	ll res=1;
	while(b)
	{
		if(b&1)res=res*a;
		a=a*a;
		b>>=1;
	}
	return res;
}
int main()
{
	init();
	read(n);
	for(register int i=1;i<=n;++i)read(d[i]);
	if(n==1)
	{
		write(d[1]==0,'\n');
		return 0;
	}
	int all=0;
	for(register int i=1;i<=n;++i)
		if(!d[i])
		{
			puts("0");
			return 0;
		}
		else all+=d[i]-1;
	if(all!=n-2)
	{
		puts("0");
		return 0;
	}
	ans=1;
	for(register int x=2;x<=n-2;++x)
		for(register int i=0,lt=V[x].size();i<lt;++i)cnt[V[x][i]]++;
	for(register int i=1;i<=n;++i)
		for(register int x=2;x<=d[i]-1;++x)
			for(register int j=0,lt=V[x].size();j<lt;++j)cnt[V[x][j]]--;
	for(register int i=1;i<=n;++i)
		if(cnt[i]<0)ans=0;
		else ans*=qexp(i,cnt[i]);
	write(ans,'\n');
	return 0;
}
posted @ 2018-07-12 21:04  HYJ_cnyali  阅读(135)  评论(0编辑  收藏  举报