Codeforces 1088E Ehab and a component choosing problem
题目链接
http://codeforces.com/problemset/problem/1088/E
题目大意
给你一棵树,每个点上有权值,你需要选出来 $k$ 个联通块,使得这 $k$ 个联通块组成的点集有 $\frac{\sum\limits_{u \in s} a_u}{k}$ ,要求最大化这个值的同时,最大化 $k$。
题目分析
显然可知,有不等式 $\frac{x + y}{a + b} \leq \frac{x}{a} + \frac{y}{b}$,意味着在 $k = 1$ 的时候一定有解。可以先使用一遍树形 $DP$ 很快的将这个解求出来。那么只需要知道的是,最多有多少个联通块满足这个要求即可。此时可以使用贪心的思路,在 $DFS$ 的时候,一旦遇到大小为 $ans$ 的联通块,就把这一枝剪掉,而且显然因为 $ans$ 已经是最优解,不存在剪掉正数的一枝之后联通块的大小还等于 $ans$ 的情况。 $DFS$ 一遍统计个数即可。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <vector> using namespace std; const int maxn = 3e5 + 5; int n, m, t; long long w[maxn]; vector <int> e[maxn]; long long ans; long long cnt = 0; long long g[maxn]; long long f[maxn]; int read(){ int x; scanf("%d", &x); return x; } int addedge(int x, int y){ e[x].push_back(y); e[y].push_back(x); return 0; } long long dfs(int x, int fa){ int y; int i, j; long long ret = -1e10; g[x] = w[x]; for(i=0;i<e[x].size();i++){ y = e[x][i]; if(y != fa){ ret = max(ret, dfs(y, x)); if(g[y] > 0){ g[x] += g[y]; } } } return max(g[x], ret); } int dfsb(int x, int fa){ int y; int i, j; long long ret = -1e10; f[x] = w[x]; for(i=0;i<e[x].size();i++){ y = e[x][i]; if(y != fa){ dfsb(y, x); if(f[y] > 0){ f[x] += f[y]; } } } if(f[x] == ans){ cnt++; f[x] = 0; } return 0; } int main(){ int i, j; int x, y; n = read(); for(i=1;i<=n;i++){ w[i] = read(); } for(i=1;i<n;i++){ x = read(); y = read(); addedge(x, y); } ans = dfs(1, -1); dfsb(1, -1); printf("%lld %lld\n", ans * cnt, cnt); return 0; }