zoukankan      html  css  js  c++  java
  • 【数学/贪心/DP】【CF1088E】 Ehab and a component choosing problem

    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, '
    ', 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

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

  • 相关阅读:
    POJ 1113 Wall
    POJ 2159 Ancient Cipher
    POJ 3253 Fence Repair
    HDU 5444 Elven Postman
    HDU 5432 Pyramid Split
    数据库 组合查询
    数据库 简单的数据查询
    数据库 聚合函数与分组
    数据库 使用DML语句更改数据
    数据库的数据完整性
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/10245226.html
Copyright © 2011-2022 走看看