[bzoj1005][HNOI2008][明明的烦恼] (高精度+prufer定理)
Description
自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?
Input
第一行为N(0 < N < = 1000),
接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1
Output
一个整数,表示不同的满足要求的树的个数,无解输出0
Sample Input
3 1 -1 -1
Sample Output
2
HINT
两棵树分别为1-2-3;1-3-2
Solution
填昨天的坑
根据prufer定理,用排列组合推出ans=(n-2)!/[(D1-1)!(D2-1)!···(Dk-1)!left!] * m^left
其中left=(n-2)-(D1-1)-(D2-1)-···-(Dk-1)
哦,还要注意特判,当无解时,高精度数组长度为0,直接输出0就行了
PoPoQQQ的代码很优雅
Code:
#include <stdio.h> #include <memory.h> #define ll long long struct num { int top; ll x[500]; num(ll a=0) { memset(x,0,sizeof x ); top=1; x[1]=a; } num operator*(const num b) { num tmp; for(int i=1; i<=top; i++) for(int j=1; j<=b.top; j++) tmp.x[i+j-1]+=x[i]*b.x[j], tmp.x[i+j]+=tmp.x[i+j-1]/100000000, tmp.x[i+j-1]%=100000000; tmp.top=top+b.top; if(!tmp.x[tmp.top]) tmp.top--; return tmp; } }ans(1); void Q_pow(int x,int p) { num tmp(x); for(;p;p>>=1,tmp=tmp*tmp) if(p&1) ans=ans*tmp; } int n,m,lef,cnt[1010]; void factorZ(int x,int d) { for(int i=2;i*i<=x;i++) while(!(x%i)) cnt[i]+=d, x/=i; if(x^1)cnt[x]+=d; } int main() { scanf("%d",&n); lef=n-2; for(int i=2;i<=lef;i++) factorZ(i,1); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); if(~x) { if(x>1) { lef-=x-1; for(int i=2;i<=x-1;i++) factorZ(i,-1); } } else ++m; } for(int i=2;i<=lef;i++) factorZ(i,-1); factorZ(m,lef); for(int i=2;i<=n;i++) if(cnt[i]) Q_pow(i,cnt[i]); printf("%lld",ans.x[ans.top]); for(int i=ans.top-1;i;i--) printf("%08lld",ans.x[i]); return 0; }