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.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Queue;

public class Main {
	int n, d;
	int[] a = new int[N];
	int ad(int x, int y){
		x += y;
		if(x>=mod)x %= mod;
		return x;
	}
	int mul(int x, int y){
		long xx = (long)x*(long)y;
		if(xx>=mod) xx %= mod;
		return (int)xx;
	}
	int dfs(int u, int fa, int dep){
		int ans = 1;
		for(int i = head[u]; i!=-1; i = edge[i].nex){
			int v = edge[i].to;
			if((v == fa)||(a[v]>a[dep]||(a[v]==a[dep]&&v>dep))||(a[dep]-a[v]>d))
				continue;
			ans = mul(ans, dfs(v, u, dep)+1);
		}
		return ans;
	}

	void input(){
		d = cin.nextInt(); n = cin.nextInt();
		for(int i = 1; i <= n; i++)	a[i] = cin.nextInt();
		init_edge();
		for(int i = 1, u, v; i < n; i++){
			u = cin.nextInt(); v = cin.nextInt();
			add(u, v); add(v, u);
		}
	}

	void work()	{
		input();
		int ans = 0;
		for(int i = 1; i <= n; i++)
			ans = ad(ans, dfs(i, i, i));
		out.println(ans%mod);
	}

	Main() {
		cin = new Scanner(System.in);
		out = new PrintWriter(System.out);
	}

	public static void main(String[] args) {
		Main e = new Main();
		e.work();
		out.close();
	}

	public Scanner cin;
	public static PrintWriter out;
	static int N = 2005;
	static int M = 2005;
	DecimalFormat df=new DecimalFormat("0.0000");
	static int inf = (int) 1e9 + 7;
	static long inf64 = (long) 1e18;
	static double eps = 1e-8;
	static double Pi = Math.PI;
	static int mod = 1000000007 ;

	class Edge{
		int from, to, nex;
		Edge(){}
		Edge(int from, int to, int nex){
			this.from = from;
			this.to = to;
			this.nex = nex;
		}
	}
	Edge[] edge = new Edge[M<<1];
	int[] head = new int[N];
	int edgenum;
	void init_edge(){for(int i = 0; i < N; i++)head[i] = -1; edgenum = 0;}
	void add(int u, int v){
		edge[edgenum] = new Edge(u, v, head[u]);
		head[u] = edgenum++;
	}

	int Pow(int x, int y) {
		int ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			y >>= 1;
			x = x * x;
		}
		return ans;
	}
	double Pow(double x, int y) {
		double ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			y >>= 1;
			x = x * x;
		}
		return ans;
	}
	int Pow_Mod(int x, int y, int mod) {
		int ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			ans %= mod;
			y >>= 1;
			x = x * x;
			x %= mod;
		}
		return ans;
	}
	long Pow(long x, long y) {
		long ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			y >>= 1;
			x = x * x;
		}
		return ans;
	}
	long Pow_Mod(long x, long y, long mod) {
		long ans = 1;
		while (y > 0) {
			if ((y & 1) > 0)
				ans *= x;
			ans %= mod;
			y >>= 1;
			x = x * x;
			x %= mod;
		}
		return ans;
	}

	int gcd(int x, int y){
		if(x>y){int tmp = x; x = y; y = tmp;}
		while(x>0){
			y %= x;
			int tmp = x; x = y; y = tmp;
		}
		return y;
	}
	int max(int x, int y) {
		return x > y ? x : y;
	}

	int min(int x, int y) {
		return x < y ? x : y;
	}

	double max(double x, double y) {
		return x > y ? x : y;
	}

	double min(double x, double y) {
		return x < y ? x : y;
	}

	long max(long x, long y) {
		return x > y ? x : y;
	}

	long min(long x, long y) {
		return x < y ? x : y;
	}

	int abs(int x) {
		return x > 0 ? x : -x;
	}

	double abs(double x) {
		return x > 0 ? x : -x;
	}

	long abs(long x) {
		return x > 0 ? x : -x;
	}

	boolean zero(double x) {
		return abs(x) < eps;
	}
	double sin(double x){return Math.sin(x);}
	double cos(double x){return Math.cos(x);}
	double tan(double x){return Math.tan(x);}
	double sqrt(double x){return Math.sqrt(x);}
}
时间: 2024-08-02 11:03:04

Codeforces 486D Valid Sets 树形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

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

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

CodeForces 158E Phone Talks 树形dp+计数

题目链接:点击打开链接 题意:给定n个点的树,常数d 给出每个点的权值,问有多少种划分方法使得划分后每个连通块里的最大权值-最小权值<=d 思路:点击打开链接 枚举每个点i 使得i是集合中的最小值. 则枚举时已经使得i是最小值,然后这个问题就变成单纯的划分问题了,上面链接里的题解已经很详尽了 import java.io.PrintWriter; import java.text.DecimalFormat; import java.util.ArrayDeque; import java.ut

CF 486D vailid set 树形DP

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 following con

Codeforces 123E Maze(树形DP+期望)

[题目链接] http://codeforces.com/problemset/problem/123/E [题目大意] 给出一棵,给出从每个点出发的概率和以每个点为终点的概率,求出每次按照dfs序从起点到达终点的期望. [题解] 首先对于期望计算有X(x,y)=X(x)*X(y),所以对于每次dfs寻路只要求出其起点到终点的期望步数,乘上起点的概率和终点的概率即可.对于一个固定起点和终点的dfs寻路,我们可以发现如果一个点在必要路径上,那么这条路被走过的期望一定为1,如果不在必要路线上,那么走

Vijos p1770 大内密探 树形DP+计数

4天终于做出来了,没错我就是这么蒟蒻.教训还是很多的. 建议大家以后编树形DP不要用记忆化搜索,回溯转移状态个人感觉更有条理性. 大神题解传送门 by iwtwiioi 我的题解大家可以看注释"//"部分 本题我用的树形DP中dp[x][fa][need]表示编号为x的节点的父亲选(1)没选(0),x的父亲需(1)不需要(0)其他节点来覆盖. 若父亲节点选了,则need肯定为0,所以不存在fa==1而need==1的状态,相当于浪费了¼的空间.毕竟数据范围比较小,而且程序要有可读性!程

bzoj 4424: Cf19E Fairy &amp;&amp; codeforces 19E. Fairy【树形dp】

参考:https://blog.csdn.net/heheda_is_an_oier/article/details/51131641 这个找奇偶环的dp1真是巧妙,感觉像tarjan一样 首先分情况讨论,如果没有奇环,每条边都可以删:如果有一个奇环,奇环上隋边山:否则,删被所有奇环覆盖且没被任何一个偶环覆盖的边 那么重点就是怎样找到所有的奇环和偶环 用树形dp来搞,设f[i]记录经过第i条边的奇环数,g[i]记录经过第i条边的偶环数,因为是边的编号而存的是双向边,所以dp的时候用i>>1表示

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

题意:给出一棵树,并给出每个节点上的权值,求有多少个连通子块的最大值与最小值的差不超过d. 对于每个顶点建立一颗树,然后找比它价值大的   或者   价值相等且之前没有被当作顶点建立树的点,这样就避免重复了. dp[x]表示包涵x且以x为顶点的连通子树的个数,dp[x] = ∏ (dp[son[x]] + 1). 注意要用long long . #include<iostream> #include<iostream> #include<cstdio> #include