BZOJ 1211 树的计数
http://www.lydsy.com/JudgeOnline/problem.php?id=1211
思路:每一个prufer编码都代表了一棵树,而点的度数,代表了它在prufer编码中出现的次数+1,因此,我们就知道每个点在prufer编码中出现的次数,用组合数就可以解决:
最后的式子约一下是: cnt!/(∏(du[i]-1)!)
要分解质因数,不然会爆longlong
#include<cstdio> #include<cmath> #include<iostream> #include<algorithm> #include<cstring> #define ll long long ll s[50]; int p[20005],n,du[200005],num[20005]; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||'9'<ch){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } bool jud(int x){ for (int i=2;i<=sqrt(x);i++) if (x%i==0) return 0; return 1; } void init(){ for (int i=2;i<=150;i++) if (jud(i)) p[++p[0]]=i; } void solve(ll x,int v){ if (x==0) return; for (int i=1;i<=p[0];i++){ if (x<=1) return; while (x%p[i]==0){ num[i]+=v; x/=p[i]; } } } int main(){ n=read(); s[1]=1; s[0]=1; for (int i=2;i<=22;i++) s[i]=s[i-1]*i; init(); ll ans=1,tot=0; for (int i=1;i<=n;i++){ du[i]=read(),du[i]--,tot+=du[i]; } if (n==1){ if (tot==-1) puts("1"); else puts("0"); return 0; } for (int i=1;i<=n;i++){ if (du[i]<0) { puts("0"); return 0; } } if (tot!=n-2){ puts("0"); return 0; } solve(s[n-2],1); for (int i=1;i<=n;i++) solve(s[du[i]],-1); for (int i=1;i<=p[0];i++) for (int j=1;j<=num[i];j++) ans*=p[i]; printf("%lld\n",ans); return 0; }