本题难想的是状态设计,因为要做到不重不漏,所以我们设计状态为f[i][j]表示以i为根,子树中到i点最大距离为j的方案数。
那么在更新的时候,只要根据新的子树和之前所有的子树的关系即可更新,因为很多j都可以成为答案,如果再枚举一维就会超过复杂度
因此使用前缀和优化,来降维到二维dp
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=4e5+10; const int mod=1e9+7; int h[N],ne[N],e[N],idx; ll f[5050][5050]; ll sum[5050][5050]; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int n,m,k; int in[N]; ll tmp[5050]; void init(){ int i,j; for(i=0;i<=n;i++){ h[i]=-1; in[i]=0; for(j=0;j<=n;j++){ f[i][j]=0; sum[i][j]=0; } } } void cal(int u,int v) { for(int i=1;i<=k;i++) tmp[i]=f[u][i]*sum[v][min(i-1,k-i-1)]%mod; for(int i=1;i<=k;i++) tmp[i]=(tmp[i]+sum[u][min(i,k-i)]*f[v][i-1])%mod; for(int i=1;i<=k/2;i++) tmp[i]=(tmp[i]+mod-f[u][i]*f[v][i-1]%mod)%mod; for(int i=1;i<=k;i++) { f[u][i]=(f[u][i]+tmp[i]+f[v][i-1])%mod; sum[u][i]=(sum[u][i-1]+f[u][i])%mod; } } void dfs(int u,int fa){ int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; dfs(j,u); cal(u,j); } if(in[u]){ for(i=1;i<=k;i++) f[u][i]=f[u][i]*2%mod; f[u][0]=1; } sum[u][0]=f[u][0]; for(i=1;i<=k;i++){ sum[u][i]=(sum[u][i-1]+f[u][i])%mod; } } int main(){ ios::sync_with_stdio(false); cin>>n>>m>>k; init(); int i; for(i=1;i<n;i++){ int a,b; cin>>a>>b; add(a,b); add(b,a); } for(i=1;i<=m;i++){ int x; cin>>x; in[x]=1; } dfs(1,-1); cout<<sum[1][k]<<endl; }View Code