蓝魔*

题意

将一颗(n(1 leq n leq 2000))个结点的树,分成(t(1leq 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;
}

原文地址:https://www.cnblogs.com/zgglj-com/p/10043564.html