树
Time Limit: 10 Sec Memory Limit: 256 MB
Description
![【Foreign】树 [prufer编码][DP] 【Foreign】树 [prufer编码][DP]](https://image.miaokee.com:8440/aHR0cHM6Ly9pbWFnZXMyMDE1LmNuYmxvZ3MuY29tL2Jsb2cvMTEwOTQ0NS8yMDE3MDMvMTEwOTQ0NS0yMDE3MDMwMTIxMDMzMTExMC0xMjc0MzgyNzU5LnBuZw%3D%3D.png?w=700&webp=1)
Input
![【Foreign】树 [prufer编码][DP] 【Foreign】树 [prufer编码][DP]](https://image.miaokee.com:8440/aHR0cHM6Ly9pbWFnZXMyMDE1LmNuYmxvZ3MuY29tL2Jsb2cvMTEwOTQ0NS8yMDE3MDMvMTEwOTQ0NS0yMDE3MDMwMTIxMDM1MTIzNS0xMzg3NDYxNjI3LnBuZw%3D%3D.png?w=700&webp=1)
Output
![【Foreign】树 [prufer编码][DP] 【Foreign】树 [prufer编码][DP]](https://image.miaokee.com:8440/aHR0cHM6Ly9pbWFnZXMyMDE1LmNuYmxvZ3MuY29tL2Jsb2cvMTEwOTQ0NS8yMDE3MDMvMTEwOTQ0NS0yMDE3MDMwMTIxMDM1NjA0OC02MjI1NDM1NTcucG5n.png?w=700&webp=1)
Sample Input
3
2 2 1
Sample Output
3 3 2
HINT
![【Foreign】树 [prufer编码][DP] 【Foreign】树 [prufer编码][DP]](https://image.miaokee.com:8440/aHR0cHM6Ly9pbWFnZXMyMDE1LmNuYmxvZ3MuY29tL2Jsb2cvMTEwOTQ0NS8yMDE3MDMvMTEwOTQ0NS0yMDE3MDMwMTIxMDQyMjQ4NS0yMTM5OTQ0NDY1LnBuZw%3D%3D.png?w=700&webp=1)
![【Foreign】树 [prufer编码][DP] 【Foreign】树 [prufer编码][DP]](https://image.miaokee.com:8440/aHR0cHM6Ly9pbWFnZXMyMDE1LmNuYmxvZ3MuY29tL2Jsb2cvMTEwOTQ0NS8yMDE3MDMvMTEwOTQ0NS0yMDE3MDMwMTIxMDQyOTI4Mi01MzkyMjk3ODkucG5n.png?w=700&webp=1)
Solution
由于是带标号的无根树的计数,于是我们运用prufer编码的性质来解题。
prufer编码的几个性质:
1.对于大小为s的树,prufer编码是一个长度为 s-2 的序列;
2.i在序列中出现的次数<deg[i];
3.一个prufer编码表示一棵树。
所以这题可以转化为求prufer编码的计数。
我们令f[i][j][k]表示前i个点,选择了j个,prufer编码长度为k的方案数。那么显然有
其中 f[i-1][j][k] 表示不选择该点的方案数,后面的式子表示选择了该点的方案数,选择该点可以在编码中出现0-deg[i]-1次,然后在编码中的出现顺序可以任意所以要乘上C。
最后如果i=1显然输出n,否则由于prufer编码是长度i-2的序列,所以输出f[n][i][i-2]。
Code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cmath>
using namespace std;
typedef long long s64;
const int ONE=;
const int MOD=; int n;
int deg[ONE];
int C[ONE][ONE];
int f[ONE][ONE][ONE]; int get()
{
int res=,Q=;char c;
while( (c=getchar())< || c> )
if(c=='-')Q=-;
res=c-;
while( (c=getchar())>= && c<= )
res=res*+c-;
return res*Q;
} void Mod(int &a)
{
if(a>MOD) a-=MOD;
} int main()
{
n=get();
for(int i=;i<=n;i++) deg[i]=get(); C[][]=;
for(int i=;i<=n;i++)
{
C[i][]=;
for(int j=;j<=n;j++)
C[i][j] = (C[i-][j] + C[i-][j-]) % MOD;
} f[][][]=;
for(int i=;i<=n;i++)
for(int j=;j<=i;j++)
for(int k=;k<=n;k++)
{
f[i][j][k] += f[i-][j][k]; Mod(f[i][j][k]);
if(!j) continue;
for(int l=; l < deg[i] && l <= k ;l++)
{
f[i][j][k] += (s64)f[i-][j-][k-l] * C[k][l] % MOD;
Mod(f[i][j][k]);
}
} for(int i=;i<=n;i++)
{
if(i==) printf("%d ",n);
else printf("%d ",f[n][i][i-]);
}
}