题意:
给你一棵树,有m个点被涂黑,让你选择一些被涂黑的点,使得这些点任意两个的距离不超过k,问你有多少种选法。
题解:
dp[i][j]表示第i个点向下深度为j的时候的方法数。
首先我们枚举x这个点向下的深度和它儿子回溯回来的时候的深度,也就是新做完一个儿子节点的时候将儿子节点的每个深度的情况与之前做的节点的每个深度的情况相乘,再是单单这个儿子的情况,最后如果这个点是被标记的,那么有取或不取两种情况。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
const int N=5e3+5;
ll dp[N][N];
struct node
{
int to,next;
}e[N*2];
int cnt,head[N],f[N];
void add(int x,int y)
{
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt++;
}
int n,m,k,dep[N];
ll g[N];
void dfs(int x,int fa)
{
for(int i=head[x];~i;i=e[i].next)
{
int ne=e[i].to;
if(ne==fa)
continue;
dfs(ne,x);
dep[x]=max(dep[x],dep[ne]+1);
for(int i=0;i<=dep[x];i++)
g[i]=dp[x][i];
for(int i=0;i<=min(dep[x],k);i++)
for(int j=0;j<=min(dep[ne],k)&&i+j+1<=k;j++)
g[max(i,j+1)]=(g[max(i,j+1)]+dp[x][i]*dp[ne][j])%mod;
for(int i=0;i<=dep[ne];i++)
g[i+1]=(g[i+1]+dp[ne][i])%mod;
for(int i=0;i<=dep[x];i++)
dp[x][i]=g[i];
}
if(f[x])
{
dp[x][0]=1;
for(int i=1;i<=min(dep[x],k);i++)
dp[x][i]=dp[x][i]*2%mod;
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
int x,y;
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++)
scanf("%d%d",&x,&y),add(x,y),add(y,x);
for(int i=1;i<=m;i++)
scanf("%d",&x),f[x]=1;
dfs(1,0);
ll ans=0;
for(int i=0;i<=dep[1];i++)
ans=(ans+dp[1][i])%mod;
printf("%lld\n",ans);
return 0;
}