[BZOJ1005][HNOI2008] 明明的烦恼
给出一棵树中所有节点的度数( −1 代表无限制),求可能的树的种类数。
0<N≤1000
嘛,这是我少有的单独为一道题写的博客,这水题卡了我一晚上,不过不能否认,这道题对现在的我来说确实很有价值,本体需要先推公式,然后分解质因数搞高精。
我们考虑用 pufer 编码来表示一棵树,根据 pufer 编码的性质:
- 任何一棵无根树都可以表示为长度为 n−2 的串;
- 一个点的度数是
d
,则它会在串中出现
d−1 次。
我们知道该已知度数的节点组成的串的总长度
len=∑i=1ndi−1
,将长度为
len
的串中的数插入到总的串中,方法有
(lenn−2)
种,而长度为
len
的串共有
(lend1−1)(len−(d1−1)d2−1)…(dn−1dn−1)
种,再算上
m
个无度数限制的节点的
ans===(lenn−2)(lend1−1)(len−(d1−1)d2−1)…(dn−1dn−1)mn−2−len(n−2)!(n−2−len)!len!⋅len!(d1−1)!(len−d1−1)!…(dn−1)!(dn−1)!0!⋅mn−2−len(n−2)!⋅mn−2−len(n−2−len)!∏ni=1(di−1)!
由于答案十分巨大,需要写高精,不过高精除比较恶心,所以我们考虑分解质因数。
/**************************************************************
Problem: 1005
User: zhangche0526
Language: C++
Result: Accepted
Time:80 ms
Memory:1344 kb
****************************************************************/
#include<iostream>
#include<cstdio>
const int MAXN=1005;
int n;
int pIdx[MAXN],pri[MAXN],pcnt,dgr[MAXN];
bool notPri[MAXN];
void initPri(int r)
{
int i,j;
for(i=2;i<=r;i++)
{
if(!notPri[i]) pri[++pcnt]=i;
for(j=1;j<=pcnt&&pri[j]*i<=r;j++)
{
notPri[pri[j]*i]=true;
if(i%pri[j]==0) break;
}
}
}
void addIdx(int x,int idx)
{
for(int i=1;i<=pcnt&&x>1;i++)
while(x%pri[i]==0)
x/=pri[i],pIdx[i]+=idx;
}
int dig[MAXN*10],dL;
int main()
{
int i,j;
initPri(1000);
scanf("%d",&n);
if(n==1)
{
scanf("%d",&dgr[1]);
if(dgr[1]==0||dgr[1]==-1) printf("1\n");
else printf("0\n");
return 0;
}
if(n==2)
{
scanf("%d%d",&dgr[1],&dgr[2]);
if(dgr[1]==1&&dgr[2]==1) printf("1\n");
else printf("0\n");
return 0;
}
int dSum=0,limNcnt=0;bool noAns=false;
for(i=1;i<=n;i++)
{
scanf("%d",&dgr[i]);
if(dgr[i]==0||dgr[i]>=n) noAns=true;
if(dgr[i]==-1)
continue;
limNcnt++;
dSum+=dgr[i]-1;
for(j=1;j<=dgr[i]-1;j++)
addIdx(j,-1);
}
for(i=1;i<=n-2;i++) addIdx(i,1);
if(noAns){printf("0\n");return 0;}
for(i=1;i<=n-2-dSum;i++) addIdx(i,-1);
addIdx(n-limNcnt,n-2-dSum);
dL=dig[1]=1;
for(i=1;i<=pcnt;i++)
{
while(pIdx[i])
{
pIdx[i]--;
for(j=1;j<=dL;j++) dig[j]*=pri[i];
for(j=1;j<dL;j++) dig[j+1]+=dig[j]/10,dig[j]%=10;
while(dig[dL]>=10)
{
dig[dL+1]+=dig[dL]/10,dig[dL]%=10;
dL++;
}
}
}
for(i=dL;i;i--)
printf("%d",dig[i]);
printf("\n");
return 0;
}