bzoj1211 [HNOI2004]树的计数

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

 

正解:$prufer$序列。
有一个结论,如果一个点的度数为$d$,那么它在$prufer$序列中出现$d-1$次。

知道这个以后我们就可以直接算了,$Ans=\frac{n-2!}{\prod_{(d-1)!}}$

注意两个细节,一是要分解质因数,二是要特判无解情况。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 
 6 using namespace std;
 7 
 8 int f[160][160],ans[160],d[160],vis[160],prime[160],n,cnt,sum;
 9 ll Ans;
10 
11 il int gi(){
12   RG int x=0,q=1; RG char ch=getchar();
13   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
14   if (ch=='-') q=-1,ch=getchar();
15   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
16   return q*x;
17 }
18 
19 il ll qpow(RG ll a,RG ll b){
20   RG ll ans=1;
21   while (b){
22     if (b&1) ans*=a; a*=a,b>>=1;
23   }
24   return ans;
25 }
26 
27 il void sieve(){
28   for (RG int i=2;i<=n;++i){
29     if (!vis[i]) prime[++cnt]=i;
30     for (RG int j=1,k;j<=cnt;++j){
31       k=i*prime[j]; if (k>n) break;
32       vis[k]=1; if (i%prime[j]==0) break;
33     }
34   }
35   return;
36 }
37 
38 il void factor(RG int n){
39   RG int x=n;
40   for (RG int i=1;i<=cnt;++i){
41     if (x%prime[i]) continue;
42     while (x%prime[i]==0) x/=prime[i],++f[n][i];
43   }
44   return;
45 }
46 
47 il void add(int *a,RG int x,RG int v){
48   for (RG int i=1;i<=cnt;++i) a[i]+=v*f[x][i]; return;
49 }
50 
51 int main(){
52 #ifndef ONLINE_JUDGE
53   freopen("count.in","r",stdin);
54   freopen("count.out","w",stdout);
55 #endif
56   n=gi(),sieve(),Ans=1;
57   for (RG int i=1;i<=n;++i){
58     d[i]=gi()-1; if (d[i]<0 && n!=1) puts("0"),exit(0); sum+=d[i];
59   }
60   if (sum!=n-2) puts("0"),exit(0);
61   for (RG int i=2;i<=n;++i) factor(i);
62   for (RG int i=2;i<=n-2;++i) add(ans,i,1);
63   for (RG int i=1;i<=n;++i)
64     for (RG int j=2;j<=d[i];++j) add(ans,j,-1);
65   for (RG int i=1;i<=cnt;++i) Ans*=qpow(prime[i],ans[i]);
66   cout<<Ans; return 0;
67 }

 

posted @ 2017-09-28 10:56  wfj_2048  阅读(190)  评论(0编辑  收藏  举报