题意很简单,大概是有多少种删边方法使得每一块大小不小于k
我们设一个树形dp,f[i][j]表示i的子树中,i所在联通块的大小为j的方案数有多少
特别的,我们用f[i][0]表示∑f[i][j] (j>=k)
那么可以写出以下转移:
f[x][i+j]+=f[x][i]*f[v][j] (j>0)
f[x][i]=f[x][i]*f[v][0]
答案就是f[root][0]
#include#include #include #include #define LL long long#define M 1000000007using namespace std;struct edge{ int v,nt; } G[4010];int h[2010],f[2010][2010],sz[2010],n,m,cnt=0;inline void ad(int& x,LL y){ x=(x+y)%M; }inline void adj(int x,int y){ G[++cnt]=(edge){ y,h[x]}; h[x]=cnt; G[++cnt]=(edge){ x,h[y]}; h[y]=cnt;}void dp(int x,int p){ f[x][1]=sz[x]=1; for(int v,i=h[x];i;i=G[i].nt) if((v=G[i].v)!=p){ dp(v,x); for(int i=sz[x];i;--i){ for(int j=sz[v];j;--j) ad(f[x][i+j],(LL)f[x][i]*f[v][j]); f[x][i]=(LL)f[x][i]*f[v][0]%M; } sz[x]+=sz[v]; } for(int i=m;i<=sz[x];++i) ad(f[x][0],f[x][i]);}int main(){ scanf("%d%d",&n,&m); for(int x,y,i=1;i