Codeforces 1088E Ehab and a component choosing problem

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;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据