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;
}

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