Description
Input
Output
Sample Input

Sample Output

Solution
题意:给你$n$个点,还有每个点的度数,问你任选$i(1leq i leq n)$个点构成树的方案数。
这种统计生成树的题,很容易想到用$prufer$序列搞。
$prufer$序列有一个很重要的性质,一个度数为$d$的点会在$prufer$序列里出现$d-1$次。
那么我们设$f[i][j][k]$表示$DP$完前$i$个点,选了其中的$j$个点,当前$prufer$序列长度为$k$。
不选:$f[i+1][j][k]+=f[i][j][k]$。
当前度数为$d+1$,也就是要把$d$个当前点插入到$prufer$序列里:$f[i+1][j+1][k+d]+=f[i][j][k] imes C[k+d][d]$。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (109) 5 #define MOD (1000000007) 6 using namespace std; 7 8 int T,n,a[N],f[N][N][N],C[N][N]; 9 10 void Preprocess() 11 { 12 C[0][0]=1; 13 for (int i=1; i<=100; ++i) 14 for (int j=0; j<=i; ++j) 15 { 16 if (j) (C[i][j]+=C[i-1][j-1])%=MOD; 17 (C[i][j]+=C[i-1][j])%=MOD; 18 } 19 } 20 21 int main() 22 { 23 Preprocess(); 24 scanf("%d",&T); 25 while (T--) 26 { 27 memset(f,0,sizeof(f)); 28 scanf("%d",&n); 29 for (int i=1; i<=n; ++i) scanf("%d",&a[i]); 30 f[0][0][0]=1; 31 for (int i=0; i<=n; ++i) 32 for (int j=0; j<=i; ++j) 33 for (int k=0; k<=n-2; ++k) 34 { 35 (f[i+1][j][k]+=f[i][j][k])%=MOD; 36 for (int d=0; d<=a[i+1]-1; ++d) 37 (f[i+1][j+1][k+d]+=1ll*f[i][j][k]*C[k+d][d]%MOD)%=MOD; 38 } 39 printf("%d",n); 40 for (int i=2; i<=n; ++i) printf(" %d",f[n][i][i-2]); puts(""); 41 } 42 }