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