Codeforces Round #277 (Div. 2) D. Valid Sets
链接:http://codeforces.com/contest/486/problem/D
解题思路:1.首先,考虑没有树的节点value情况,那就简化成了求一颗树的所有子树,用dp很容易就可以得到。
即:dp[u]=∏(dp[v]+1) ,其中u是父节点,v是子节点。
2.需要寻找节点value之差不超过d的子树,考虑到找到的子树一定会存在一个value最小的点,所以把每个节点做为根节点,
形成n颗所有节点满足 a[v]>=a[root]&&a[v]<=a[root]+d的树,把每颗树的根节点的dp[root]加起来就是总数。
3.注意中间过程的取模,同时注意出现节点value一样的情况,避免重复计算。
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <cmath> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int maxn = 2000 + 10; 10 const int MOD = 1e9 + 7; 11 12 vector<int> node[maxn]; 13 int a[maxn]; 14 long long dp[maxn]; 15 bool f[maxn]; 16 int d, n; 17 18 void dfs(int u, int root) 19 { 20 for (int i = 0; i < node[u].size(); i++) 21 { 22 f[u] = 1; 23 int v = node[u][i]; 24 if(f[v] == 0 && ((a[v] > a[root] && a[v] <= a[root] + d) || (a[v] == a[root] && v > root))) 25 { 26 dfs(v, root); 27 dp[u] = (dp[u] * (dp[v] + 1)) % MOD; 28 } 29 } 30 } 31 32 int main() 33 { 34 while(scanf("%d%d", &d, &n) != EOF) 35 { 36 for (int i = 1; i <= n; i++) 37 { 38 scanf("%d", &a[i]); 39 } 40 for (int i = 0; i < n - 1; i++) 41 { 42 int u, v; 43 scanf("%d%d", &u, &v); 44 node[u].push_back(v); 45 node[v].push_back(u); 46 } 47 int sum = 0; 48 for (int i = 1; i <= n; i++) 49 { 50 memset(f, 0, sizeof(f)); 51 for (int j = 1; j <= n; j++) 52 { 53 dp[j] = 1; 54 } 55 dfs(i, i); 56 sum = (sum + dp[i]) % MOD; 57 } 58 printf("%d ", sum); 59 } 60 61 62 63 return 0; 64 }
AC如下: