BSOJ 5445 -- 【2018雅礼】树 prufer序列 dp
BSOJ在哪我也不知道 没有链接.
对于有标号无根树的统计和有度数限制 一般采用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;
}