cfE. Ehab and a component choosing problem(贪心)

题意

题目链接

给出一棵树,每个节点有权值,选出\(k\)个联通块,最大化

\[\frac{\sum_{i \in S} a_i}{k}\]

Sol

结论:选出的\(k\)个联通块的大小是一样的且都等于最大联通块的大小

证明:因为我们是在保证分数最大的情况下才去最大化\(k\),一个很经典的结论是单独选择一个权值最大的联通块得到的分数一定是最大的,然后我们这时我们才去考虑最大化\(k\)

那么思路就很清晰了,先一遍dfs dp出最大联通块,然后再一遍dfs从下往上删就行了

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 3e5 + 10, INF = 1e18;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, a[MAXN], mx[MAXN], ans = -INF, num;
#define siz(v) ((int)v.size())
vector<int> v[MAXN];
void dfs(int x, int fa) {
    mx[x] = a[x];
    for(int i = 0; i < siz(v[x]); i++) {
        int to = v[x][i];
        if(to == fa) continue;
        dfs(to, x);
        mx[x] = max(mx[x], mx[x] + mx[to]);
    }
    ans = max(ans, mx[x]);
}
void dfs2(int x, int fa) {
    mx[x] = a[x];
    for(int i = 0; i < siz(v[x]); i++) {
        int to = v[x][i];
        if(to == fa) continue;
        dfs2(to, x);
        mx[x] = max(mx[x], mx[x] + mx[to]);
    }
    if(mx[x] == ans) num++, mx[x] = 0;
}
signed main() {
#ifndef ONLINE_JUDGE
    //freopen("a.in", "r", stdin);freopen("a.out", "w", stdout);
#endif
    N = read();
    for(int i = 1; i <= N; i++) a[i] = read();
    for(int i = 1; i <= N - 1; i++) {
        int x = read(), y = read();
        v[x].push_back(y); v[y].push_back(x);
    }
    dfs(1, 0);
    //printf("%I64d\n", ans);
    memset(mx, 0, sizeof(mx));
    dfs2(1, 0);
    cout << ans * num << " " << num;
    return 0;
}

原文地址:https://www.cnblogs.com/zwfymqz/p/10069374.html

时间: 2024-08-30 16:28:19

cfE. Ehab and a component choosing problem(贪心)的相关文章

cf1088E Ehab and a component choosing problem (树形dp)

题意(考试时看错了对着样例wa了好久..):从树上选k个连通块,使得权值的平均值最大的基础上,选的块数最多 如果不考虑块数最多的限制,肯定是只选一个权值最大的块是最好的 然后只要看这个权值最大的块有多少个不相交的就可以了 做法就是,在dp的时候,一旦找到了和最大权值相等的块,直接统计答案,然后把这一块的权值改成-inf 1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x

Codeforces Round #525 E - Ehab and a component choosing problem

题目大意: 在一棵树中 选出k个联通块 使得 这k个联通块的点权总和 / k 最大 并且这k个联通块不相互覆盖(即一个点只能属于一个联通块) 如果有多种方案,找到k最大的那种 给定n 有n个点 给定n个点的点权(点权可能出现负数) 给定这个树的n-1条边 当将所有点分成联通块后,比较各个强联通块的点权总和,绝对存在最大值,而点权总和=最大值的也可能有多个 此时 若选择了所有点权总和等于最大值的联通块,那么 /k 之后得到的 ans=这个最大值 假设继续选择次大值,那么此时 res = (ans*

CF D. Ehab and the Expected XOR Problem 贪心+位运算

code: #include <bits/stdc++.h> #define N 1000000 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int vis[N],b[N]; void solve() { int n,m,i,j,cur=1,cnt=0; memset(vis,0,sizeof(vis)); scanf("%d%d",&n,&a

HDU 4974 A simple water problem(贪心)

HDU 4974 A simple water problem 题目链接 签到题,很容易贪心得到答案是(sum + 1) / 2和ai最大值的最大值 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 100005; typedef long long ll; int t, n; ll a, Max, sum; int main(

Codeforces 442B Andrey and Problem(贪心)

题目链接:Codeforces 442B Andrey and Problem 题目大意:Andrey有一个问题,想要朋友们为自己出一道题,现在他有n个朋友,每个朋友想出题目的概率为pi,但是他可以同时向多个人寻求帮助,不过他只能要一道题,也就是如果他向两个人寻求帮助,如果两个人都成功出题,也是不可以的. 解题思路:贪心,从概率最大的人开始考虑,如果询问他使得概率变大,则要询问. #include <cstdio> #include <cstring> #include <a

uva 10026 Shoemaker&#39;s Problem(贪心+排序)

虽然是个水题,但是在一些细节上wa了几次,好像不支持'\b'退格符号,我用在了输出空格那,结果wa了...白白 wa了几次...题意是看的题解..今天只写了两道题,速度有点慢,得加快了,以后得先认真读懂题目,题目读懂了 就相当于做出来一半然后仔细动脑想想,有想法了再敲,不能盲目的做题.另外,热烈祝贺今天c++ primer看到 了100页 思路: 这道题是让给的数据是每件工作需要做的天数和每耽误一天所需要的费用,让求一个序列使得付费最小,如果有相同答 案把字典树最小的输出...输出的是序号,该件

Codeforces Round #563 (Div. 2) D、Ehab and the Expected XOR Problem

D. Ehab and the Expected XOR Problem Given two integers n and x, construct an array that satisfies the following conditions: for any element ai in the array, 1≤ai<2^n there is no non-empty subsegment with bitwise XOR equal to 0 or x, its length l sho

cf 1174 D Ehab and the Expected XOR Problem

cf 1174 D Ehab and the Expected XOR Problem 题意 在1~\(2^n\)范围内找到一个最长的序列,使得该序列的每一个子串异或后不等于0和x 题解 假设该序列为a,那么前缀异或和b[i] = a[i]^a[i-1]^...^a[0],如果b之间异或都不会等于0和x,那么a之间也不会. #include <cstdio> #include <cstring> int main() { int n, x; while(~scanf("%

CodeForces 1325E - Ehab&#39;s REAL Number Theory Problem【质因子+】

题意: ??给定一个数组 \(a\) ,数组中任意一个元素的因子数不超过 \(7\) ,找出一个最短的子序列,满足该子序列之积为完全平方数.输出其长度. 数据范围:\(1≤n≤10^5,1≤a_i≤10^6\) 分析: ??首先,对于数组中的每个元素,如果其因子中包含有一个完全平方数,那么可以把该完全平方数除去,不影响最后的结果. ??然后,可以发现,当一个数的因子个数 \(\leq 7\) 时,其包含的质因子个数 \(\leq 2\).(如果有3个质因子,那么至少有 \(8\) 个因子)当我们