BSOJ 5445 -- 【2018雅礼】树 prufer序列 dp

BSOJ在哪我也不知道 没有链接.

avatar

对于有标号无根树的统计和有度数限制 一般采用prufer序列。

根据prufer序列 容易知道 某个点的出现次数+1为当前点的度数。

对于这道题 考虑设f[i][j]表示前i个点填了prufer序列j个位置时的方案数。

不过这样做存在的问题是 最后我们要求恰好k个点形成的长度为k-2的prufer序列的方案数。

如果设这个状态 这个状态到底有多少个点我们无从得知。

所以需要再开一维状态 表示当前使用了k个点。

转移 :由于状态相当于答案 对于j个位置时相当于只有j个位置时的答案 所以要扩充w个位置时 那么显然C(w+j,w).

复杂度n^4 不过跑不满。

const ll MAXN=102;
ll n;
ll a[MAXN];
ll fac[MAXN],inv[MAXN],f[MAXN][MAXN][MAXN];//f[i][j][k]表示前i个点选出了使用了j个点构成长度为k的prufer序列的方案数.
inline ll ksm(ll b,ll p)
{
	ll cnt=1;
	while(p)
	{
		if(p&1)cnt=cnt*b%mod;
		b=b*b%mod;p=p>>1;
	}
	return cnt;
}
inline ll C(ll a,ll b){return a<b?0:fac[a]*inv[b]%mod*inv[a-b]%mod;}
signed main()
{
	freopen("1.in","r",stdin);
	get(n);fac[0]=1;f[0][0][0]=1;
	rep(1,n,i)get(a[i]),fac[i]=fac[i-1]*i%mod;
	inv[n]=ksm(fac[n],mod-2);
	fep(n-1,0,i)inv[i]=inv[i+1]*(i+1)%mod;
	rep(1,n,i)
	{
		rep(0,i,j)
		{
			rep(0,n,k)
			{
				f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mod;
				if(j>=1)rep(1,a[i],l)if(k-l+1>=0)f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k-l+1]*C(k,l-1))%mod;
				else break;
			}
		}
	}
	put_(n);rep(2,n,i)put_(f[n][i][i-2]);
	return 0;
}
posted @ 2020-05-06 11:31  chdy  阅读(197)  评论(0编辑  收藏  举报