题意
给定一个 n 个节点的有点权的树,求满足块中最大值与最小值之差小于等于 d 的联通块数。
n≤2000,d≤2000,ai≤2000
思路
不难想到枚举每个点作为最小值的答案,以选定的点为根进行 dp。
定义 dpi 表示以 i 为根的子树包含 i 点的联通块数量,那么只需要考虑点权在 (art,art+d] 之间与点权等于 art 但是编号小于 rt(这一步为了去重)的点。
我们令不满足上述要求的店 dp 值为零,则有转移方程:
dpi=∏(dpson+1)
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #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; };
|