Nowcoder20811.蓝魔法师(树形背包)
作者:互联网
“你,你认错人了。我真的,真的不是食人魔。”--蓝魔法师
给出一棵树,求有多少种删边方案,使得删后的图每个连通块大小小于等于k,两种方案不同当且仅当存在一条边在一个方案中被删除,而在另一个方案中未被删除,答案对998244353取模
#include<bits/stdc++.h>
using namespace std;
const int maxn=2005;
const int mod=998244353;
typedef long long ll;
ll f[maxn][maxn];
//f(i,j)表示i的子树内i本身的连通块大小为j的方案数
//不如换成每个点独立,有多少种连边方案
//那么f(i,1)一开始是1
//对i的每个儿子v,可以选择连边,那么f(i,j+k)+=f(i,j)*f(v,k)
//也可以选择不连边,那么f(i,j)*=f(v,k)
vector<int> g[maxn];
int size[maxn];
int n,m;
void dfs (int x,int pre) {
f[x][1]=1;
size[x]=1;
for (int y:g[x]) {
if (y==pre) continue;
dfs(y,x);
long long sum=0;
for (int i=1;i<=min(m,size[y]);i++) {
sum=(sum+f[y][i])%mod;
}
for (int i=min(m,size[x]);i>=1;i--) {
for (int j=min(m,size[y]);j>=1;j--) {
if (i+j<=m) {
f[x][i+j]=(f[x][i+j]+f[x][i]*f[y][j]%mod)%mod;
}
}
f[x][i]*=sum;
f[x][i]%=mod;
}
size[x]+=size[y];
}
}
int main () {
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1,0);
ll ans=0;
for (int i=1;i<=m;i++) ans=(ans+f[1][i])%mod;
printf("%lld\n",ans);
}
标签:方案,Nowcoder20811,long,魔法师,int,树形,maxn,--,size 来源: https://www.cnblogs.com/zhanglichen/p/14605783.html