CF486D Valid Sets 题解

题意

给定一个 \(n\) 个节点的有点权的树,求满足块中最大值与最小值之差小于等于 \(d\) 的联通块数。

\(n\le2000,d\le2000,a_i\le2000\)

思路

不难想到枚举每个点作为最小值的答案,以选定的点为根进行 dp。

定义 \(dp_i\) 表示以 \(i\) 为根的子树包含 \(i\) 点的联通块数量,那么只需要考虑点权在 \((a_rt,a_rt+d]\) 之间与点权等于 \(a_rt\) 但是编号小于 \(rt\)(这一步为了去重)的点。

我们令不满足上述要求的店 \(dp\) 值为零,则有转移方程:

\(dp_i=\prod (dp_son+1)\)

code
#include <bits/stdc++.h>
#define int long long
#define chmax(x, y) x = max(x, y)
#define chmin(x, y) x = min(x, y)
#define SP << " " <<
#define fish signed
using namespace std;
mt19937 rnd(1209);
const int INF = 0x3f3f3f3f3f3f3f3f, mod = 1e9 + 7;
const int N = 2e3 + 10;
vector<int> e[N];
int dp[N], n, d, now, a[N];
int ans;
void dfs(int u, int fa)
{
    dp[u] = 1;
    for(auto v : e[u])
    {
        if(v == fa) continue;
        dfs(v, u);
        if(dp[v]) dp[u] = dp[u] * (dp[v] + 1) % mod;
    }
    if(a[u] > a[now] + d || a[u] < a[now] || a[u] == a[now] && u > now) dp[u] = 0;
}
fish main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin >> d >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    for(int i = 1, u, v; i < n; i ++) cin >> u >> v, e[u].push_back(v), e[v].push_back(u);
    for(int i = 1; i <= n; i ++) now = i, dfs(i, 0), ans = (dp[i] + ans) % mod;
    cout << ans << "\n";
    return 0;
};
posted @ 2024-12-21 09:18  lfyszy  阅读(12)  评论(0)    收藏  举报