首页 > 代码库 > CodeForces 486D Valid Sets
CodeForces 486D Valid Sets
题意:
给定一棵n(2000)个节点的树 每个节点上有个数字 问 有多少棵子树满足树中最大数字与最小数字的差不超过d
思路:
根据数据猜复杂度可能为n^2 想到尝试树形dp
假如枚举现在树中的最大值 那么最小值可以求出 这时不在数值范围内的节点都可以标记掉
那么假设这个最大值的点我一定选取 那么就可以dp出一定选这个点的情况下子树的种类数
假设u是父节点 v是子节点 那么已知dp[u]=dp[u]*dp[v] 特殊的v如果是叶子 那么dp[v]=2 即可选可不选 如果u是不是根 那么dp[u]最后要+1 因为可以不选u
我们发现这样dp还是不可以的 因为假设现在枚举的最大值为10 树中可能有两个10的节点是连通的 这时计数就会出问题 不过没关系 我们刚才的定义是“一定选某个点” 那么假设我们dp算过了“一定选一号10节点”的情况 这时就可以把一号10节点标记成坏节点 下次处理二号10节点的时候就可以一定不选刚才的点了
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<map> #include<set> #include<vector> #include<queue> #include<cstdlib> #include<ctime> #include<cmath> using namespace std; typedef long long LL; #define N 2010 #define mod 1000000007 int n, d, m, big, small; int val[N], a[N], vis[N]; struct edge { int v, next; } ed[N * 2]; int head[N], tot; LL dp[N], ans; void add(int u, int v) { ed[tot].v = v; ed[tot].next = head[u]; head[u] = tot++; } void dfs(int u, int key) { vis[u] = 1; dp[u] = 1; for (int i = head[u]; ~i; i = ed[i].next) { int v = ed[i].v; if (!vis[v]) { dfs(v, 1); dp[u] = (dp[u] * dp[v]) % mod; } } dp[u] = (dp[u] + key) % mod; vis[u] = 0; } int main() { scanf("%d%d", &d, &n); for (int i = 1; i <= n; i++) { scanf("%d", &val[i]); a[i] = val[i]; head[i] = -1; } tot = 0; for (int i = 2; i <= n; i++) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); } sort(a + 1, a + n + 1); m = unique(a + 1, a + n + 1) - a - 1; for (int i = m; i >= 1; i--) { big = a[i]; small = big - d; for (int j = 1; j <= n; j++) { if (val[j] < small || val[j] > big) vis[j] = 1; else vis[j] = 0; } for (int j = 1; j <= n; j++) { if (!vis[j] && val[j] == big) { dfs(j, 0); ans = (ans + dp[j]) % mod; vis[j] = 1; } } //cout << a[i] << " " << ans << endl; } cout << ans << endl; return 0; }
CodeForces 486D Valid Sets
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。