P2290 [HNOI2004]树的计数

P2290 [HNOI2004]树的计数

传送门

思路:pruferprufer序列板子题。

显然有公式:(n2)!i=1n(degree[i]1)!\dfrac{(n-2)!}{\sum\limits_{i=1}^n(degree[i]-1)!}

因为此题数据范围较大,可能会爆long longlong\ long,但是题目保证答案不会超过LLLL,所以我们考虑转化为乘法做。

显然上述公式等价于从n2n-2个数,分别选出d[1]1d[1]-1个位置放1,d[2]2d[2]-2个位置放22,d[n]1\dots,d[n]-1个位置放nn,所以前提是必须满足i=1n(degree[i]1)=n2\sum\limits_{i=1}^n(degree[i]-1)=n-2

所以每次我们相当于从剩下的数选出d[i]1d[i]-1个数,即为C(n2sum,d[i]1)C(n-2-sum,d[i]-1)

第一次:C(n2,d[1]1)C(n-2,d[1]-1)

第二次: C(n2(d[1]1),d[2]1)C(n-2-(d[1]-1),d[2]-1)

第三次:C(n2(d[1]1)(d[2]1),d[3]1)C(n-2-(d[1]-1)-(d[2]-1),d[3]-1)

依次类推,再根据乘法原理即可算出答案,这样巧妙避免除法爆LLLL.

此外此题需要注意,n=1n=1需要特判,因为公式是从 n2n-2计算的,还需对度数为0点的特判,显然存在这样的孤点,不可能构成树。

n==1n==1时,如果d[1]==0d[1]==0显然只有唯一解,否则无解,因为孤点不可能有度数。

时间复杂度:O(n2)O(n^2)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=150+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first 
#define se second
ll c[N][N],d[N],sum,ans=1;
void fun(int n){
	for(int i=0;i<=n;i++) c[i][i]=c[i][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
}
int main(){
	int n,ok=1;
	scanf("%d",&n);
	if(n==1){	//特判n=1的情况. 
	 scanf("%d",&d[1]);
	  puts(d[1]?"0":"1");
	  return 0;
	 }
	for(int i=1;i<=n;i++){
		scanf("%lld",&d[i]),d[i]--,sum+=d[i];
		if(d[i]==-1) ok=0;
	}
	if(sum!=n-2||!ok) return puts("0"),0;
	fun(n),sum=0;
	for(int i=1;i<=n;i++)
		ans*=c[n-2-sum][d[i]],sum+=d[i];
	printf("%lld\n",ans);
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章