HDU6540 Neko and tree(树形dp)

本题难想的是状态设计,因为要做到不重不漏,所以我们设计状态为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

 

posted @ 2020-10-29 20:29  朝暮不思  阅读(169)  评论(0编辑  收藏  举报