地址:http://acm.hdu.edu.cn/showproblem.php?pid=6540
思路:树状DP
参考博客:http://www.cnblogs.com/CJLHY/p/10890357.html
dp[i][j]:表示在点i 为根节点的子树中,距离点i 最远距离为j的方案数,
即对于i子树中的方案{ai1,ai2,ai3,...,aik}, ai1-aik都属于i子树,
且方案中最远的点ai到点i 的距离为 j.
则dp[u][max(i,j+1)]=Sum{d[u][i]*dp[v][j]} 其中u为父节点,v为子节点 d[u][i]=dp[u][i]即dp[u][i]不影响状态转移
Code:
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long LL;
const int MAX_N=5e3+5;
const int MAX_S=5e3+5;
const LL MOD=1e9+7;
int n,m,s;
vector<int> e[MAX_N];
int h[MAX_N];
LL d[MAX_N];
LL dp[MAX_N][MAX_S];
bool boo[MAX_N];
void DFS(int u,int pre);
int main()
{
scanf("%d%d%d",&n,&m,&s);
int u,v;
for(int i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=0;i<m;boo[u]=true,++i)
scanf("%d",&u);
DFS(1,0);
LL res=0;
for(int i=0;i<=h[1];++i)
res=(res+dp[1][i])%MOD;
printf("%lld\n",res);
return 0;
}
void DFS(int u,int pre)
{
for(auto v:e[u])
if(v!=pre){
DFS(v,u);
h[u]=max(h[u],h[v]+1);
for(int i=0;i<=h[u];++i)
d[i]=dp[u][i];
for(int i=0;i<=h[u]&&i<=s;++i)
for(int j=0;j<=h[v]&&j<=s;++j)
if(i+j+1<=s) d[max(i,j+1)]=(d[max(i,j+1)]+dp[u][i]*dp[v][j]%MOD)%MOD;
for(int i=0;i<=h[v];++i)
d[i+1]=(d[i+1]+dp[v][i])%MOD;
for(int i=0;i<=h[u];++i)
dp[u][i]=d[i];
}
if(boo[u]){
dp[u][0]=1;
for(int i=1;i<=s&&i<=h[u];++i)
dp[u][i]=dp[u][i]*2%MOD; //是否包含u共两种可能
}
}