Codeforces 486D Valid Sets:Tree dp【n遍O(n)的dp】

题目链接:http://codeforces.com/problemset/problem/486/D

题意:

  给你一棵树,n个节点,每个节点的点权为a[i]。

  问你有多少个连通子图,使得子图中的max(a[i]) - min(a[i]) <= d。

  ps.连通子图的定义:

    如果一个点集V为一个连通子图,则对于任意两点a,b∈V,有a到b路径上的所有点u∈V。

题解:

  因为要保证max(a[i]) - min(a[i]) <= d,所以可以人为地选出一个点rt作为点权最大的点。

  这样在求以rt为最大点的连通子图个数时,只用考虑点权不超过a[rt]的点。

  然而如果有两个点i,j的点权相同,分别以i,j作为最大点的两堆子图中会有重复。

  所以可以定义一下:当以rt作为最大点时,所有点权与a[rt]相等的点,它们的节点编号id[i]必须大于id[rt]。

  这样就能避免重复了。

  所以最终答案 = ∑(以i为最大点的连通子图个数)

  求以i为最大点的连通子图个数,只需一遍O(n)的dp就行。

  注意,当前这是一棵无根树。以下所说的“i的子树”意思是:从i出发往叶子方向的那一堆点。

  假设当前以rt作为最大点。  

  则加入连通子图的点i必须满足:

    (1)a[rt]-a[i]<=d(保证满足题目条件)

    (2)a[i]<=a[rt](保证a[rt]为最大点)

    (3)如果a[i]==a[rt] && i!=rt,则要满足rt<i(避免重复计数)

  表示状态:

    dp[i] = numbers

    表示节点i肯定要选,i的子树所构成的合法连通子图个数

  找出答案:

    每次ans += dp[rt]

  如何转移:

    dp[i] = ∏ (dp[son]+1)

  边界条件:

    对于叶子结点leaf: dp[leaf] = 1

  总复杂度O(n^2)。

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #define MAX_N 2005
 6 #define MOD 1000000007
 7
 8 using namespace std;
 9
10 int n,d;
11 int a[MAX_N];
12 vector<int> edge[MAX_N];
13
14 void read()
15 {
16     cin>>d>>n;
17     for(int i=1;i<=n;i++) cin>>a[i];
18     int x,y;
19     for(int i=1;i<n;i++)
20     {
21         cin>>x>>y;
22         edge[x].push_back(y);
23         edge[y].push_back(x);
24     }
25 }
26
27 long long dfs(int now,int p,int rt,int mx)
28 {
29     if(mx-a[now]>d || a[now]>mx || (a[now]==mx && p!=-1 && now<rt)) return 0;
30     long long res=1;
31     for(int i=0;i<edge[now].size();i++)
32     {
33         int temp=edge[now][i];
34         if(temp!=p) res=res*(dfs(temp,now,rt,mx)+1)%MOD;
35     }
36     return res;
37 }
38
39 void work()
40 {
41     long long ans=0;
42     for(int i=1;i<=n;i++) ans=(ans+dfs(i,-1,i,a[i]))%MOD;
43     cout<<ans<<endl;
44 }
45
46 int main()
47 {
48     read();
49     work();
50 }

原文地址:https://www.cnblogs.com/Leohh/p/8274235.html

时间: 2024-10-10 22:58:26

Codeforces 486D Valid Sets:Tree dp【n遍O(n)的dp】的相关文章

Codeforces 486D Valid Sets(暴力)

题目链接:Codeforces 486D Valid Sets 题目大意:给定一棵树,每个节点有个权值,现在要选定一些节点,要求非空,并且maxVal-minVal不大于d.问说有多 少种选择方法. 解题思路:枚举每个节点作为根节点,默认根节点为权值最大的节点,然后各个孩子节点用乘法原理即可. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using n

Codeforces 486D Valid Sets 树形dp+计数

题目链接:点击打开链接 题意:给定常数d 和 n,表示n个点的树,每个点有点权 问:有多少个点集使得点集中的点两两可达且最大点权-最小点权<=d 思路: 对于每个点,计算包含这个点且这个点作为点集中的最小点权时的个数,枚举每个点. import java.io.PrintWriter; import java.text.DecimalFormat; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.

CodeForces 486D Valid Sets

题意: 给定一棵n(2000)个节点的树  每个节点上有个数字  问  有多少棵子树满足树中最大数字与最小数字的差不超过d 思路: 根据数据猜复杂度可能为n^2  想到尝试树形dp 假如枚举现在树中的最大值  那么最小值可以求出  这时不在数值范围内的节点都可以标记掉 那么假设这个最大值的点我一定选取  那么就可以dp出一定选这个点的情况下子树的种类数 假设u是父节点  v是子节点  那么已知dp[u]=dp[u]*dp[v]  特殊的v如果是叶子  那么dp[v]=2  即可选可不选  如果u

Codeforces Round #277 (Div. 2) D. Valid Sets DP

D. Valid Sets As you know, an undirected connected graph with n nodes and n - 1 edges is called a tree. You are given an integer d and a tree consisting of n nodes. Each node i has a value ai associated with it. We call a set S of tree nodes valid if

Codeforces 461B Appleman and Tree(木dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每一个节点的父亲节点,以及每一个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量.保证每一个联通分量有且仅有1个黑色节点.问有多少种切割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的切割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include &l

codeforces 161D - Distance in Tree(树形dp)

题目大意: 求出树上距离为k的点对有多少个. 思路分析: dp[i][j] 表示 i 的子树中和 i 的距离为 j 的点数有多少个.注意dp[i] [0] 永远是1的. 然后在处理完一颗子树后,就把自身的dp 更新. 更新之前更新答案. 如果这颗子树到 i 有 x 个距离为j的.那么答案就要加上 dp[i] [ k-j-1] * x; #include <iostream> #include <cstdio> #include <cstring> #include &l

Codeforces 461B Appleman and Tree(树形dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每个节点的父亲节点,以及每个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量,保证每个联通分量有且仅有1个黑色节点.问有多少种分割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的分割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include <c

CodeForces 461B Appleman and Tree:Tree dp

题目链接:http://codeforces.com/problemset/problem/461/B 题意: 给你一棵树(编号从0到n-1,0为根节点),每个节点有黑白两种颜色,其中黑色节点有k+1个. 现在让你删掉k条边,使得这棵树变成k+1个连通块,并且要保证每个连通块中有且仅有一个黑色节点. 问你删边的方案有多少种. 题解: 表示状态: dp[i][0/1] = numbers 表示在节点i所在的连通块中有(1)或没有(0)黑色节点时,节点i的子树的删边方法数 因为总要保证每个连通块中有

codeforces 416B. Appleman and Tree 树形dp

题目链接 Fill a DP table such as the following bottom-up: DP[v][0] = the number of ways that the subtree rooted at vertex v has no black vertex. DP[v][1] = the number of ways that the subtree rooted at vertex v has one black vertex. The recursion pseudo