习题:Valid Sets(树DP)

题目

传送门

思路

我们考虑一个联通块的情况实际上只取决于他的最大值和最小值

所以我们考虑哪一个点作为最大值,之后设\(dp[i]\)为以i为根节点的子树有多少种符合方案的情况

转移即为\(dp[i]=\prod_{v\in son} (dp[v]+1)\)

很明显,这一定会有重复的方案出现

所以我们强行规定这个联通块内的与最大值相等的元素的编号一定大于我们枚举的编号

dfs的时候改一下dp判断的条件即可

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int mod=1e9+7;
int d,n;
int val[2005];
vector<int> g[2005];
long long dp[2005];
long long ans;
void dfs(int u,int fa,int rt)
{
    dp[u]=1;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i];
        if(v!=fa&&val[rt]-val[v]<=d&&val[rt]>val[v])
        {
            dfs(v,u,rt);
            dp[u]=dp[u]*(dp[v]+1)%mod;
        }
        else if(v!=fa&&val[rt]==val[v]&&v<rt)
        {
            dfs(v,u,rt);
            dp[u]=dp[u]*(dp[v]+1)%mod;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>d>>n;
    for(int i=1;i<=n;i++)
        cin>>val[i];
    for(int i=1,u,v;i<n;i++)
    {
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for(int i=1;i<=n;i++)
    {
        memset(dp,0,sizeof(dp));
        dfs(i,0,i);
        ans=(ans+dp[i])%mod;
    }
    cout<<ans;
    return 0;
}
posted @ 2020-07-31 11:20  loney_s  阅读(141)  评论(0)    收藏  举报