Description

给定一棵 \(n\) 个节点的树,点有点权 \(a_u\),可能为负。现在请你在树上找出 \(k~(1~\leq~k~\leq~n)\) 个不相交集合,使得每个集合中的每对点都可以通过本集合中的点互相到达,假设选出的 \(k\) 个集合的并集为 \(s\),要求最大化:

\[\frac{\sum_{u \in s} a_u}{k}
\]

如果有多解请输出 \(k\) 最大的解

Input

第一行是节点个数 \(n\)。

下面一行 \(n\) 个数代表点权

下面 \(n - 1\) 行描述这棵树

Output

输出一行两个整数,分别是选出的点权和以及 \(k\)

不约分

Solution

结论:在不限元素个数时,要求选出元素的平均值最大,则最优解一定为只选择元素值最大的元素。如果有多个元素的值最大,选择个数对答案无影响。

证明:数学归纳法,先将元素按照权值降序排序。当只选择 \(1\) 个元素的时候,显然选择第一个元素最优。考虑已经选了 \(k\) 个元素,现在要决定是否选 \(k + 1\) 个元素。由于是降序排序的,则这个元素的权值显然不大于前面所有元素的平均值。设前面所有元素的平均值为 \(a\),第 \(k + 1\) 个元素的权值为 \(w\),则选择该元素后的平均值为 \(\frac{ak + w}{k + 1}\) 。要判断它和原平均值 \(a\) 的关系,则对它们做差,记 \(\delta~=~\frac{ak + w}{k + 1} - a\)

\[\delta~=~\frac{ak}{k + 1} + \frac{w}{k + 1}- \frac{a(k + 1)}{k + 1}~=~\frac{w}{k + 1} - \frac{a}{k + 1}~=~\frac{w - a}{k + 1}
\]

前面已经论证 \(w~\leq~a\),于是 \(\delta~\leq~0\)。当且仅当 \(w~=~a\) 即前 \(k + 1\) 个元素权值相同时,等号成立。证毕。

于是根据这个结论,问题就被转化成了:求一个符合要求的集合使得这个集合的权值和尽可能大,然后统计有多少个这样的不想交的集合。

第一问显然可以直接树形DP,设 \(f_u\) 为 \(u\) 的子树中必选 \(u\) 的集合的最大权值,则有:

\[f_u~=~\sum_{to} \max(f_{to}, 0)
\]

于是就可以求出最大的权值了。考虑统计答案时,由于要求的是不相交的集合,所以我们每将一个集合加入贡献以后再将这个集合删掉,一边统计答案一遍DP就可以了。

Code

#include <cstdio>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#define putchar(o) \
puts("I am a cheater!")
#endif
#define rg register
#define ci const int
#define cl const long long typedef long long int ll; namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
} template <typename T>
inline void qr(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
} template <typename T>
inline void ReadDb(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
if (ch == '.') {
ch = IPT::GetChar();
double base = 1;
while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
}
if (lst == '-') x = -x;
} namespace OPT {
char buf[120];
} template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
rg int top=0;
do {OPT::buf[++top] = char(x % 10 + '0');} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
} const int maxn = 300010;
const int maxm = 600010; struct Edge {
int to;
Edge *nxt;
};
Edge edge[maxm], *hd[maxn];int ecnt;
inline void cont(ci from, ci to) {
Edge &e = edge[++ecnt];
e.to = to; e.nxt = hd[from]; hd[from] = &e;
} int n, cnt;
ll ans = -(1ll << 62);
ll MU[maxn], frog[maxn]; void reading();
void dfs(ci, ci, ci); int main() {
freopen("1.in", "r", stdin);
qr(n);
for (rg int i = 1; i <= n; ++i) qr(MU[i]);
reading();
dfs(1, 0, 1); dfs(1, 0, 0);
qw(ans * cnt, ' ', true); qw(cnt, '\n', true);
return 0;
} void reading() {
int a, b;
for (rg int i = 1; i < n; ++i) {
a = b = 0; qr(a); qr(b);
cont(a, b); cont(b, a);
}
} void dfs(ci u, ci fa, ci op) {
frog[u] = MU[u];
for (Edge *e = hd[u]; e; e = e->nxt) {
int &to = e->to;
if (to == fa) continue;
dfs(to, u, op);
if (frog[to] > 0) frog[u] += frog[to];
}
if (op) ans = std::max(ans, frog[u]);
else if (frog[u] == ans) ++cnt, frog[u] = -(1ll << 60);
}

Summary

选择任意个元素使得平均值最大时,只选择最大的就好啦

【数学/贪心/DP】【CF1088E】 Ehab and a component choosing problem的更多相关文章

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

    题意(考试时看错了对着样例wa了好久..):从树上选k个连通块,使得权值的平均值最大的基础上,选的块数最多 如果不考虑块数最多的限制,肯定是只选一个权值最大的块是最好的 然后只要看这个权值最大的块有多 ...

  2. Codeforces 1088E Ehab and a component choosing problem

    Ehab and a component choosing problem 如果有多个连接件那么这几个连接件一定是一样大的, 所以我们先找到值最大的连通块这个肯定是分数的答案. dp[ i ]表示对于 ...

  3. Codeforces Round #525 (Div. 2)E. Ehab and a component choosing problem

    E. Ehab and a component choosing problem 题目链接:https://codeforces.com/contest/1088/problem/E 题意: 给出一个 ...

  4. Codeforces Round #525 (Div. 2) E. Ehab and a component choosing problem 数学

    题意:给出树 求最大的sigma(a)/k k是选取的联通快个数   联通快不相交 思路: 这题和1个序列求最大的连续a 的平均值  这里先要满足最大平均值  而首先要满足最大  也就是一个数的时候可 ...

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

    题意 题目链接 给出一棵树,每个节点有权值,选出\(k\)个联通块,最大化 \[\frac{\sum_{i \in S} a_i}{k}\] Sol 结论:选出的\(k\)个联通块的大小是一样的且都等 ...

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

    题目大意: 在一棵树中 选出k个联通块 使得 这k个联通块的点权总和 / k 最大 并且这k个联通块不相互覆盖(即一个点只能属于一个联通块) 如果有多种方案,找到k最大的那种 给定n 有n个点 给定n ...

  7. 【BZOJ-3174】拯救小矮人 贪心 + DP

    3174: [Tjoi2013]拯救小矮人 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 686  Solved: 357[Submit][Status ...

  8. BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP

    BZOJ_3174_[Tjoi2013]拯救小矮人_贪心+DP Description 一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯.即:一个小矮人站在另一小矮人的 肩膀 ...

  9. 洛谷P4823 拯救小矮人 [TJOI2013] 贪心+dp

    正解:贪心+dp 解题报告: 传送门! 我以前好像碰到过这题的说,,,有可能是做过类似的题qwq? 首先考虑这种显然是dp?就f[i][j]:决策到了地i个人,跑了j个的最大高度,不断更新j的上限就得 ...

随机推荐

  1. PytorchZerotoAll学习笔记(一)

    Pytorch的安装请参考torch的官方文档,传送门:https://pytorch.org/get-started/locally/ Numpy的复习 如果你之前没有学过Numpy的话,建议去看看 ...

  2. 《The Mythical Man-Month(人月神话)》读后感(1)

    临近考试周,这里我通过平时阅读的<人月神话>十九个章节和知乎.简书等网页中网友们对<人月神话>的读后感,对书中各个章节进行简单的总结,以下均为个人手打观点的思考与整合,仅供大家 ...

  3. PHP中的__toString() 是什么东西

    __toString()  是魔术方法的一种,具体用途是当一个对象被当作字符串对待的时候,会触发这个魔术方法 以下说明摘自PHP官方手册 public string __toString ( void ...

  4. Django_QueryDict

    介绍 class QueryDict(MultiValueDict): """ A specialized MultiValueDict which represents ...

  5. babel无法编译?

    ECMAScript 6(ES6)的发展或者说普及之快可以说是难以想象的,对很多人来说ECMAScript 5(ES5)都还普及呢.现代浏览器对ES6新特新或多或少的有些支持,但支持度不高,所以要想在 ...

  6. 第十三次作业psp

    psp 进度条 代码累积折线图 博文累积折线图 psp饼状图

  7. 第七周psp例行报告

    本周psp 本周进度条 代码累积折线图 博文字数累积折线图 饼状图

  8. Chapter 8 面向对象设计

    设计也是一个建模的活动,在设计阶段将集中研究系统的软件实现问题包括体系结构设计.详细设计.用户界面设计和数据库设计等.通常设计活动分为系统设计和详细设计两个主要阶段.软件设计要遵循模块化.耦合度和内聚 ...

  9. 第一个Sprint冲刺成果

    组长:李咏江,组员:叶煜稳,谢洪跃,周伟雄 进程:第一个算法功能完成

  10. 结对作业(1.0版)(bug1已修复)

    import java.awt.EventQueue; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing ...