题意

给出一棵树,求有多少种删边方案,使得删后的图每个连通块大小小于等于k,两种方案不同当且仅当存在一条边在一个方案中被删除,而在另一个方案中未被删除,答案对998244353取模。

分析

我们定义表示为i的子树的所有联通块大小不超过k,并且i所在联通块大小为j的方案数。

对于每条边,假设为 u —— v ,我们都有两种选择,删与不删,如果删去的话,u的联通块大小不会变,如果不删的话,u的联通块大小就会变成两个联通块大小之和。

树形dp+背包

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define int long long
const int inf = 0x3f3f3f3f;
const int maxn = 2110;
const int M = 998244353;
int n,m,k,ok;

vector<int> v[maxn];

int dp[maxn][maxn];     //i的子树的所有联通块大小不超过k,并且i所在联通块大小为j

int sz[maxn];

void dfs(int u,int pre)
{   
    dp[u][1] = sz[u] = 1;
    for(auto i : v[u])
    {
        if(i == pre) continue;
        dfs(i,u);
        int sum = 0;
        for(int j = 1; j <= sz[i] && j <= k; j++) sum = (sum+dp[i][j])%M;
        for(int j = min(sz[u],k); j >= 1; j--)      //枚举u的联通块大小
        {
            for(int w = min(sz[i],k); w >= 1; w--)      //大的先更新
            {
                if(j+w <= k) dp[u][j+w] = (dp[u][j+w] + dp[u][j]*dp[i][w]%M)%M; 
            }
            //断开这条边
            dp[u][j] = dp[u][j]*sum%M;
        }
        sz[u] += sz[i];
    }
}

signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    cin>>n>>k;
    for(int i = 2,x,y; i <= n; i++) 
    {
        cin>>x>>y;
        v[x].push_back(y);
        v[y].push_back(x);
    }
    dfs(1,0);
    int ans = 0;
    for(int i = 1; i <= k; i++) ans = (ans + dp[1][i])%M;
    cout<<ans<<endl;
    return 0;
}