首页 > 代码库 > 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