【BZOJ 1211】HNOI2004]树的计数(组合数学+Purfer序列)

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序列是通过寻找一棵树最小的叶节点 A A A,把与这个叶节点相连的非根节点 B B B加入到数组中,并删除 ( A , B ) (A,B) A,B,直到剩下两个点为止,
这n-2个数就是Purfer序列,每颗树只有一个Purfer序列。并且每个点最多在Purfer序列种出现 ( 度 数 − 1 ) (度数-1) (1)次。
因此最后的答案为
( n − 2 ) ! / ∏ i = 1 n ( d e e d [ i ] − 1 ) (n-2)!/\prod_{i=1}^n(deed[i]-1) (n2)!/i=1n(deed[i]1)
在这个过程中,乘法会爆long long,因此我们需要进行质因数分解优化。
把参与运算的每个数质因数分解,除法的时候直接消去即可。
最终在把剩下的数乘起来。

#include
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<

你可能感兴趣的:(数论--数学,OJ--BZOJ)