JZOJ 5068.树

Problem

Description
有n个点,它们从1到n进行标号,第i个点的限制为度数不能超过A[i].
现在对于每个s (1 <= s <= n),问从这n个点中选出一些点组成大小为s的有标号无根树的方案数。
Input
第一行一个整数n.
第二行n个整数表示A[i].
Output
输出一行n个整数,第i个整数表示s=i时的答案。答案模1004535809.
Sample Input
3
2 2 1
Sample Output
3 3 2

Solution

首先看到无根树,想到Prufer序列。
一棵无根树对应着一个Prufer序列,且有一个性质特别地重要:假设有一点x度数为d[x],那么在Prufer序列中会出现d[x]-1次。
证明:
首先点i度数为d[i],说明有d[i]个点连着他,将与之连着的d[i-1]个点删掉的时候,假设没被删的与之连着的点为j,那么会有几种情况:
①当前没被删的节点只剩2个。那么得证。
②当前没被删的节点超过2个:
⑴删去与j连着的点及“子树”,此时最后剩下i和j两个点,转①。
⑵此时i点是叶子节点,那么i点可能是所有叶子节点中标号最小的,得证。否则就转②。
我们可以很容易地得知,选出的点集为A,这些点在Prufer序列中出现了Ci次,那么这些点组成一棵树的方案为:

|A|!ΠiACi!

所以我们列DP。
刚刚开始我想到的显然是 f[i][j] 表示做到i选了j个,但是序列长度维护不了。
所以设 f[i][j][k] 表示做到i选了j个,选了这j个数,Prufer序列长度为k的方案数。
DP方程:
f[i][j][k]+=f[i1][j][k]

f[i][j][k]+=f[i1][j1][kl]1l!

选i个答案为 f[n][i][i2](i2)!

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 105
#define mo 1004535809
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
LL f[N][N][N];
LL a[N],jc[N],ny[N];
LL i,j,k,l,n,m,tmp;
LL ksm(LL x,LL y){
    LL res=1;
    while (y){
        if (y%2) res=(res*x)%mo;
        x=(x*x)%mo;
        y/=2;
    }
    return res;
}
int main(){
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    scanf("%lld",&n);
    fo(i,1,n) scanf("%lld",&a[i]);
    jc[0]=jc[1]=ny[0]=ny[1]=1;
    fo(i,2,n) jc[i]=(jc[i-1]*i)%mo;
    ny[n]=ksm(jc[n],mo-2);
    fd(i,n-1,1) ny[i]=(ny[i+1]*(i+1))%mo;
    f[0][0][0]=1;
    fo(i,1,n){
        fo(j,0,n){
            fo(k,0,n){
                f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mo;
                tmp=min(k,a[i]-1);
                if(j)fo(l,0,tmp)f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k-l]*ny[l])%mo;
            }
        }
    }
    printf("%lld",n);
    fo(i,2,n)printf(" %lld",(f[n][i][i-2]*jc[i-2])%mo);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值