今天小a在纸上研究树的形态,众所周知的,有芭蕉树,樟树,函树,平衡树,树套树等等。那么小a今天在研究的就是其中的平衡树啦。
小a认为一棵平衡树的定义为一个n个点,从1到n编号,n-1条边,且任意两点间一定存在唯一一条简单路径,且n>=k。
现在小a看到一棵很大很大的树,足足有n个节点,这里n一定大于等于k!为了方便起见,它想把这个树删去某些边,使得剩下的若干个联通块都满足是平衡树。这时,小b走过来,不屑一顾的说,如果我一条边都不删,那么也算一棵平衡树咯。
小a对于小b的不屑感到很不爽,并问小b,你能算出我删边的方案总数使得满足我的条件吗?两个删边的方案A,B不同当且仅当存在某一条边属于集合A且不属于集合B,或者存在某一条边属于集合B且不属于集合A。为了让你方便,你只要告诉我答案对1000000007(1e9+7)取模就行了。
小b犯了难,找到了身为程序猿的你。
Hint:
样例解释,
第一种方案为不删边,
第二种方案为删去2 3这一条边,
第三种方案为删去3 4这一条边。
Input
第一行读入两个正整数n,k(1<=k<=n<=2000)。
接下来n-1行,每行两个正整数A,B ( 1<= A,B<= n),表示A与B有一条边相连,题目保证在不删任何一条边的情况下是一棵平衡树。
Output
一个整数,表示答案对1000000007(1e9+7)取模后的值。
Input示例
5 2
1 2
2 3
3 4
4 5
Output示例
3
题解
dp[u][i]表示u为根规模为i且其余树为平衡树的方案数,容易得到dp[u][i+j]+=dp[u][i]*dp[v][j];记dp[u][0]表示u为根合法的方案数,则每次转移前dp[u][i]=dp[u][i]*dp[v][0];
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<set>
#include<ctime>
#include<vector>
#include<cmath>
#include<algorithm>
#include<map>
#define mod 1000000007
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int tot,n,k,dp[2005][2005],size[2005];
int ret[4005],Next[4005],Head[4005];
inline void ins(int u,int v)
{
ret[++tot]=v;Next[tot]=Head[u];Head[u]=tot;
}
void dfs(int u,int pre)
{
dp[u][1]=1;size[u]=1;
for (int i=Head[u];i;i=Next[i])
{
int v=ret[i];
if (v==pre) continue;
dfs(v,u);
for (int i=size[u];i>0;i--)
{
for (int j=1;j<=size[v];j++)
dp[u][i+j]=(dp[u][i+j]+(ll)dp[u][i]*dp[v][j]%mod)%mod;
dp[u][i]=(ll)dp[u][i]*dp[v][0]%mod;
}
size[u]+=size[v];
}
for (int i=k;i<=size[u];i++) dp[u][0]=(dp[u][0]+dp[u][i])%mod;
}
int main()
{
n=read();k=read();
for (int i=1;i<n;i++)
{
int u=read(),v=read();
ins(u,v);ins(v,u);
}
dfs(1,0);
printf("%d",dp[1][0]);
return 0;
}