1211: [HNOI2004]树的计数
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 3149 Solved: 1181
[Submit][Status][Discuss]
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
在写这道题之前我们先了解一下什么叫做Purfer序列。
Purfer序列是通过寻找一棵树最小的叶节点
,把与这个叶节点相连的非根节点
加入到数组中,并删除
,直到剩下两个点为止,
这n-2个数就是Purfer序列,每颗树只有一个Purfer序列。并且每个点最多在Purfer序列种出现
次。
因此最后的答案为
。
在这个过程中,乘法会爆long long,因此我们需要进行质因数分解优化。
把参与运算的每个数质因数分解,除法的时候直接消去即可。
最终在把剩下的数乘起来。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
const int INF = 0x3f3f3f3f;
typedef long long ll;
ll a[maxn];
ll cnt[maxn];
void solve(ll n,ll kk){
for(ll i=2;i*i<=n;i++){
while(n%i==0){
cnt[i]+=kk;
n/=i;
}
}
cnt[n]+=kk;
return ;
}
int main(){
ll n;
cin>>n;
ll sum=0;
for(ll i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
for(ll i=1;i<=n;i++){
if(!a[i]&&n>1){
cout<<0<<endl;
return 0;
}
}
if(sum!=2*n-2){
cout<<0<<endl;
return 0;
}
if(n<=2){
cout<<1<<endl;
return 0;
}
for(ll i=1;i<=n-2;i++){
solve(i,1);
}
ll ans=1;
for(ll i=1;i<=n;i++){
for(ll j=2;j<a[i];j++){
solve(j,-1);
}
}
for(ll i=1;i<=n;i++){
for(ll j=1;j<=cnt[i];j++){
ans*=i;
}
}
cout<<ans<<endl;
return 0;
}