1211: [HNOI2004]树的计数
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1154 Solved: 350
[ Submit][ Status]
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
【题解】可直接参考08年周梦宇的论文。关键是数据中存在一些无法构成树的情况,需要特判掉。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define LL long long
typedef int pp[4100];
pp w,ans,p;
inline void cheng(pp &f,int t)
{
for(int i=1;i<=2000;i++)f[i]*=t;
for(int i=1;i<2000;i++)
if(f[i]>9){
f[i+1]+=f[i]/10;f[i]%=10;
}
}
inline bool pan(pp f,pp t,int k)
{
for(int i=2000;i;i--)
if(f[i]>t[i+k])return 1;
else if(f[i]<t[i+k])return 0;
return 1;
}
inline void halt()
{
printf("0\n");
exit(0);
}
inline void chu(pp f,pp t)
{
int lenf=2000,lent=2000,num;
while(!f[lenf])lenf--;
while(!t[lent])lent--;
for(int i=lenf;i>=(lenf-lent+1);i--)t[i]=t[i-(lenf-lent)];
for(int i=lenf-lent;i;i--)t[i]=0;
int tail=0;num=lenf-lent+1;
while(lenf)
if(pan(f,t,tail)){
ans[num]++;
for(int i=lenf;i;i--) f[i]-=t[i+tail];
for(int i=1;i<=lenf;i++)
if (f[i]<0) f[i]+=10,f[i+1]--;
while ((!f[lenf]) && (lenf>0)) lenf--;
}else {
tail++,num--;
if(num<=0)halt();
}
}
int main()
{
memset(p,0,sizeof(p));
memset(w,0,sizeof(w));
memset(ans,0,sizeof(ans));
int n,tot=0;
scanf("%d",&n);
w[1]=p[1]=1;
for(int l,i=1;i<=n;i++)
{
scanf("%d",&l);tot+=(l-1);
if((!l) && n>1)halt();
for(int j=1;j<=l-1;j++)cheng(p,j);
}
if(tot!=n-2 && n>1)halt();
for(int i=1;i<=n-2;i++)cheng(w,i);
chu(w,p);int l=2000;
while(!ans[l])l--;
for(int i=l;i;i--)printf("%d",ans[i]);
printf("\n");
return 0;
}