HDU 6091

思路来自 某FXXL

不过复杂度咋算的..

/*
HDU 6091 - Rikka with Match [ 树形DP ]  |  2017 Multi-University Training Contest 5
题意:
	给出N个点的树,求去边的方案数使得 去边后最大匹配数是M的倍数
	限制: N<=5e4, M<=200
分析:
	设 DP[u][i][0] 表示 以点 u 为根的子树 最大匹配数模 m 为 i 时,且 u 点没有匹配的方案数
	   DP[u][i][1] 表示 以点 u 为根的子树 最大匹配数模 m 为 i 时,且 u 点匹配上的方案数
	得到对于 u 的某个子节点 v 对 u 的更新(讨论(u,v)的边连与不连)
		DP[u][k][0] += ∑ [i+j==k] 2 * DP[u][i][0] * DP[v][j][1] + 1 * DP[u][i][0] * DP[v][j][0]
		DP[u][k][1] += ∑ [i+j==k] 2 * DP[u][i][1] * ( DP[v][j][0] + DP[v][j][1] )
		DP[u][k][1]	+= ∑ [i+j==k-1] DP[u][i][0] * DP[v][j][0]
	
	每次在合并的时候更新u节点的取值范围,即 size[u] = min(size[u]+size[v], m)   这样复杂度大概 O(nm)(???)
*/
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL MOD = 998244353;
const int N = 5e4+5;
const int M = 205;
vector<int> G[N];
int t, n, m;
int size[N];
LL dp[N][M][2];
LL tmp[M<<1][2];
void solve(int u, int v)
{
    memset(tmp, 0, sizeof(tmp));
    for (int i = 0; i <= size[u]; i++)
        for (int j = 0; j <= size[v]; j++)
        {
            tmp[i+j][1] += 2 * dp[u][i][1] * (dp[v][j][0]+dp[v][j][1]);
            tmp[i+j][1] %= MOD;
            tmp[i+j+1][1] += dp[u][i][0] * dp[v][j][0];
            tmp[i+j+1][1] %= MOD;
            tmp[i+j][0] += 2 * dp[u][i][0]*dp[v][j][1] + dp[u][i][0]*dp[v][j][0];
            tmp[i+j][0] %= MOD;
        }
    for (int i = 0; i < m; i++)
    {
        dp[u][i][0] = (tmp[i][0] + tmp[i+m][0]) % MOD;
        dp[u][i][1] = (tmp[i][1] + tmp[i+m][1]) % MOD;
    }
    size[u] =  min(m, size[u]+size[v]);
}
void dfs(int u, int pre)
{
    memset(dp[u], 0, sizeof(dp[u]));
    dp[u][0][0] = 1;
    size[u] = 1;
    for (auto & v : G[u])
    {
        if (v == pre) continue;
        dfs(v, u);
        solve(u, v);
    }
}
int main()
{
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) G[i].clear();
        for (int i = 1; i < n; i++)
        {
            int u, v; scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        dfs(1, 1);
        int ans = (dp[1][0][0]+dp[1][0][1]) % MOD;
        printf("%d
", ans);
    }
}

  

原文地址:https://www.cnblogs.com/nicetomeetu/p/7360556.html