P2290 [HNOI2004]樹的計數
思路:板子題。
顯然有公式:
因爲此題數據範圍較大,可能會爆,但是題目保證答案不會超過,所以我們考慮轉化爲乘法做。
顯然上述公式等價於從個數,分別選出個位置放1,個位置放,個位置放,所以前提是必須滿足
所以每次我們相當於從剩下的數選出個數,即爲。
第一次:
第二次:
第三次:。
依次類推,再根據乘法原理即可算出答案,這樣巧妙避免除法爆.
此外此題需要注意,需要特判,因爲公式是從 計算的,還需對度數爲0點的特判,顯然存在這樣的孤點,不可能構成樹。
當,如果顯然只有唯一解,否則無解,因爲孤點不可能有度數。
時間複雜度:
#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;
}