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