[HNOI2004]树的计数
题目描述
输入输出格式
输入格式:
输入文件第一行是一个正整数n,表示树有n个结点。第二行有n个数,第i个数表示di,即树的第i个结点的度数。其中1<=n<=150,输入数据保证满足条件的树不超过10^17个。
输出格式:
输出满足条件的树有多少棵。
输入输出样输入样例#1:
4 2 1 2 1
输出样例#1:
2
Prüfer编码与Cayley公式
给出几个链接:
http://www.matrix67.com/blog/archives/682
http://blog.csdn.net/justesss/article/details/38129101
http://blog.csdn.net/yuyanggo/article/details/49951597
总的来说,就是说:
1.n个节点的生成树有n^(n-2)
2.对于n个点,度为di
方案数=(n-2)!/(∏(di-1)!)
对于这题直接套第2个公式
分解质因子再化简
注意判断树能否构成
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int d[1001],n,vis[1001],prime[1001],pre[1001],tot,sum; 7 long long s[1001],ans; 8 long long qpow(long long x,int y) 9 { 10 long long res=1; 11 while (y) 12 { 13 if (y&1) res=res*x; 14 x=x*x; 15 y=y/2; 16 } 17 return res; 18 } 19 int main() 20 { 21 int i,j; 22 cin>>n; 23 for (i=1; i<=n; i++) 24 { 25 scanf("%d",&d[i]); 26 if (d[i]==0&&1!=n) 27 { 28 cout<<0; 29 return 0; 30 } 31 sum+=d[i]-1; 32 for (j=2; j<=d[i]-1; j++) 33 s[j]--; 34 } 35 if (sum!=n-2) 36 { 37 cout<<0; 38 return 0; 39 } 40 for (i=2; i<=n-2; i++) 41 s[i]++; 42 for (i=2; i<=n; i++) 43 { 44 if (vis[i]==0) 45 { 46 pre[i]=i; 47 tot++; 48 prime[tot]=i; 49 } 50 for (j=1; j<=tot; j++) 51 { 52 if (prime[j]*i>n) break; 53 vis[i*prime[j]]=1; 54 pre[i*prime[j]]=prime[j]; 55 if (i%prime[j]==0) break; 56 } 57 } 58 ans=1; 59 for (i=n; i>=2; i--) 60 if (pre[i]!=i) 61 { 62 s[pre[i]]+=s[i]; 63 s[i/pre[i]]+=s[i]; 64 s[i]=0; 65 } 66 for (i=n; i>=2; i--) 67 { 68 if (s[i]<0) 69 { 70 cout<<0; 71 return 0; 72 } 73 ans*=qpow(i,s[i]); 74 } 75 cout<<ans; 76 }