每日一题 蓝魔法师 (树形dp)
蓝魔法师
https://ac.nowcoder.com/acm/problem/20811
一.题意
给出 n 个节点,以及最大连通块数目 k ,
可以删掉一些边,求连通块数目小于等于 k 的方案数。
二.题解
三.代码:
#include<bits/stdc++.h> #define mp make_pair #define pb push_back #define ll long long #define fi first #define se second #define inf 0x3f3f3f3f #define io std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; const int manx=1e5+5; const int N=2e3+5; const int mod=1e9+7; const int mo=998244353; vector<ll>g[N]; ll dp[N][N],sz[N]; ll n,ans,k; void dfs(ll u, ll pre){ dp[u][1]=1; sz[u]=1; for(auto v: g[u]){ if(v==pre) continue; dfs(v,u); ll m=min(k,sz[v]),up=min(k,sz[u]); ll sum=0; for(int i=1;i<=m;i++) sum+=dp[v][i],sum%=mo; for(int i=up;i;i--){ for(int j=m;j;j--) if(i+j<=k) dp[u][i+j]+=dp[u][i]*dp[v][j]%mo,dp[u][i+j]%=mo; dp[u][i]*=sum,dp[u][i]%=mo; } sz[u]+=sz[v]; } } int main(){ io; cin>>n>>k; for(int i=1;i<n;i++){ ll u,v; cin>>u>>v; g[u].pb(v); g[v].pb(u); } dfs(1,1); for(int i=1;i<=k;i++) ans+=dp[1][i],ans%=mo; cout<<ans<<endl; return 0; }