codeforces 724F. Uniformly Branched Trees

8 篇文章 0 订阅
2 篇文章 0 订阅

题目链接http://codeforces.com/problemset/problem/724/F
题目大意:给定三个数n,d,mod,求有多少种n个点的不同构的树满足:除了度数为1的结点外,其余结点的度数均为d。答案对质数mod取模。
数据范围:1 ≤ n ≤ 1000, 2 ≤ d ≤ 10, 10^8 ≤ mod ≤ 10^9

题解:看到题目不难想到是树形dp。首先我们考虑有根树,f[i][j][k]表示有 i 个结点,根结点有 j 棵子树,每棵子树大小不超过k的方案数。有两种情况:
1.所有的子树大小都小于k,转移到f[i][j][k-1]。
2.有 l (l>0)棵子树大小为k,结果应为f[i-l*k][j-l][k-1]*C(f[k][d-1][k-1]+l-1,l)。注:C(X+l-1,l)表示从X种方案中选取 l 种,可以重复。
求出了有根树的方案数,我们需要转化成无根树。上述方案会重复计算答案的值,是因为同一棵树选取不同的结点作根时在 f 中表现出的状态是不同的,所以我们应该找到一个特殊的结点作为根,即树的重心,因为树的重心只有一个或两个。我们知道,对于一棵树的重心,它的子树大小不会超过n/2,所以答案为f[n][d][n/2]。而当一棵树有两个重心时,说明这棵树的重心的最大子树恰好有n/2(n为偶数)个点,此时应该减去重复(即两个重心在 f 中表示的状态不同时)的方案数C(f[n/2][d-1][n/2],2)。
最后,当n<=2时没有度数为d的点,此时特判一下就可以了。
时间复杂度O(n^2*d^2)

代码如下:

#include <algorithm>
#include <cstdio>
int f[1005][11][1005],g[1005][11],ine[11],n,d,mo;
int inv(int x)
{
    int i=1,y=mo-2;
    for (;y;y>>=1,x=1ll*x*x%mo)
        if (y&1) i=1ll*i*x%mo;
    return i;
}
int main()
{
    scanf("%d%d%d\n",&n,&d,&mo);
    for (int i=0;i<=n;i++) f[1][0][i]=1;
    for (int i=1;i<=d;i++) g[1][i]=1;
    for (int i=1;i<=d;i++) ine[i]=inv(i);
    for (int i=2;i<=n;i++)
    {
        for (int j=1;j<=d;j++)
        {
            for (int k=1;k<i;k++)
                for (int l=1;l<=j && l*k<=i;l++)
                    f[i][j][k]=(f[i][j][k]+1ll*f[i-l*k][j-l][k-1]*g[k][l])%mo;
            for (int k=1;k<=n;k++) f[i][j][k]=(f[i][j][k]+f[i][j][k-1])%mo;
        }
        g[i][1]=f[i][d-1][n];
        for (int j=2;j<=d;j++)
            g[i][j]=1ll*g[i][j-1]*(f[i][d-1][n]+j-1)%mo*ine[j]%mo;
    }
    int ans;
    if (n<=2) ans=1;
        else ans=f[n][d][n/2];
    if (n>2 && !(n&1))
        ans=(ans-1ll*(f[n/2][d-1][n/2]-1)*f[n/2][d-1][n/2]%mo*ine[2]%mo+mo)%mo;
    printf("%d\n",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值