蓝魔法师 - 牛客

题意

将一颗\(n(1 \leq n \leq 2000)\)个结点的树,分成\(t(1\leq t \leq n)\)个连通块,且每个连通块的大小都小于或者等于\(k(1 \leq k \leq 2000)\),求划分方案数?

题解

\(dp[i][j]\):以\(i\)为根的子树向父亲结点\(u\)提供\(j\)个点的贡献

\[dp[fa[i]][cnt_1 + cnt_2]=\sum{dp[fa[i]][cnt_1] * dp[i][cnt_2]} \]

复杂度\(O(nk)\)

代码

const int N = 2005;
const int mod = 998244353;

int n, k;
int dp[N][N], sz[N], temp[N];

vector<int> G[N];

void addedge(int u, int v) {
    G[u].pb(v);
    G[v].pb(u);
}

#define debug(x) cout << "____" << x << "____" << endl

void DFS(int u, int p) {
    dp[u][1] = sz[u] = 1;
    for (auto v : G[u]) if (v != p) {
        DFS(v, u);

        mem(temp, 0);

        Rep(i, 1, sz[u]) Rep(j, 0, min(k - i, sz[v])) temp[i + j] = (temp[i + j] + 1ll * dp[u][i] * dp[v][j] % mod) % mod;
        memcpy(dp[u], temp, sizeof(temp));

        sz[u] += sz[v];
    }
    Rep (i, 1, k) dp[u][0] = (dp[u][0] + dp[u][i]) % mod;
}

int main()
{
    cin >> n >> k;
    rep (i, 1, n) {
        int u, v;
        cin >> u >> v;
        addedge(u, v);
    }

    DFS(1, 0);

    int ans = 0;
    Rep (i, 1, k) ans = (ans + dp[1][i]) % mod;
    pr(ans);

    return 0;
}

posted @ 2018-11-30 13:09  天之道,利而不害  阅读(258)  评论(0编辑  收藏  举报