【51Nod1353】树

今天小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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值