【洛谷P2290】树的计数
题目
题目链接:https://www.luogu.com.cn/problem/P2290
一个有 \(n\) 个节点的树,设它的节点分别为 \(v_1,v_2,\ldots,v_n\),已知第 \(i\) 个节点 \(v_i\) 的度数为 \(d_i\),问满足这样的条件的不同的树有多少棵。
\(1\le n\le 150\),保证满足条件的树不超过 \(10^{17}\) 个。
思路
既然点有了度数限制,那么等价于 prufer 序列上这个点出现次数必须是 \(\mathrm{deg}_i-1\)。
问题转化为一个长度为 \(n-2\) 的序列,\(i\) 出现次数为 \(\mathrm{deg}_i-1\) 的方案数。显然等于
\[\frac{(n-2)!}{\Pi^{n}_{i=1}(\mathrm{deg}_i-1)!}
\]
由于题目保证了答案不超过 long long 范围,那么直接分解质因数最后再乘起来即可。
时间复杂度 \(O(n^2)\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=155;
int n,deg[N],cnt[N][N],a[N];
ll ans;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
int p=i;
for (int j=2;j<=n;j++)
{
cnt[i][j]=cnt[i-1][j];
for (;p%j==0;p/=j) cnt[i][j]++;
}
}
for (int j=1;j<=n;j++)
a[j]+=cnt[n-2][j];
for (int i=1;i<=n;i++)
{
scanf("%d",°[i]);
if (!deg[i]) return printf("%d",deg[1]==0),0;
for (int j=1;j<=n;j++)
a[j]-=cnt[deg[i]-1][j];
deg[0]+=deg[i]-1;
}
if (deg[0]!=n-2) return printf("0"),0;
ans=1;
for (int i=1;i<=n;i++)
for (;a[i];a[i]--) ans*=i;
printf("%lld",ans);
return 0;
}

浙公网安备 33010602011771号