46th-ICPC(昆明)F.Find the Maximum

F.Find the Maximum

题意

给定一棵包含 n n n个节点的数,每个节点都有一个权值 b i b_i bi,你需要找出一条长度大于 1 1 1的简单路径,然后找到一个实数 x x x最大化 ∑ u ∈ V ( x 2 + b u x ) ∣ V ∣ \frac{\sum_{u\in V}(x^{2}+b_ux)}{|V|} VuV(x2+bux)的值,其中 V V V表示这条简单路径上节点的集合。

题解

首先对上述式子进行化简:
∑ u ∈ V ( − x 2 + b u x ) ∣ V ∣ = − ∣ V ∣ x 2 + ( ∑ u ∈ V b u ) x ∣ V ∣ = − x 2 + ∑ u ∈ V b u ∣ V ∣ x \frac{\sum_{u\in V}(-x^{2}+b_ux)}{|V|}=\frac{-|V|x^{2}+(\sum_{u\in V}b_u)x}{|V|}=-x^{2}+\frac{\sum_{u\in V}b_u}{|V|}x VuV(x2+bux)=VVx2+(uVbu)x=x2+VuVbux
其中 ∑ u ∈ V b u ∣ V ∣ \frac{\sum_{u\in V}b_u}{|V|} VuVbu为该简单路径上所有节点权值的平均值,令其等于 a v g avg avg,继续化简为:
− x 2 + a v g × x = − ( x − a v g 2 ) 2 + a v g 2 4 -x^{2}+avg\times x=-(x-\frac{avg}{2})^{2}+\frac{avg^{2}}{4} x2+avg×x=(x2avg)2+4avg2
显然最大值就等于 a v g 2 4 \frac{avg^{2}}{4} 4avg2,因此我们只需要找到平均值的正数最大值与负数最小值然后进行比较即可。
这里需要用到一个结论:要在 n n n个数中找到长度大于 1 1 1的连续子序列的平均值的最大值,其长度为 2 2 2 3 3 3时最优,可用反证法证明:
现有 4 4 4个数 a , b , c , d a,b,c,d a,b,c,d,假设取长度为 4 4 4时平均值最大。
反证:根据题意显然可以得到:
a + b + c + d 4 > a + b + c 3 , b + c + d 3 , a + b 2 , b + c 2 , c + d 2 \frac{a+b+c+d}{4}>\frac{a+b+c}{3},\frac{b+c+d}{3},\frac{a+b}{2},\frac{b+c}{2},\frac{c+d}{2} 4a+b+c+d>3a+b+c3b+c+d2a+b2b+c2c+d
= > 2 c + 2 d > 2 a + 2 b , 2 a + 2 d > 2 b + 2 c , 2 a + 2 b > 2 c + 2 d =>2c+2d>2a+2b,2a+2d>2b+2c,2a+2b>2c+2d =>2c+2d>2a+2b2a+2d>2b+2c2a+2b>2c+2d
可以发现 2 c + 2 d > 2 a + 2 b 与 2 a + 2 b > 2 c + 2 d 2c+2d>2a+2b与2a+2b>2c+2d 2c+2d>2a+2b2a+2b>2c+2d互相矛盾,因此平均值最大时不可能超过 3 3 3
代码就很简单了,注意负数平方后也可能是最大平均值。

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 5, inf = 1e9;
int n, a[N];
vector<int> h[N];
double ans1, ans2;
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	for(int i = 1; i < n; i++) {
		int u, v;
		scanf("%d%d", &u, &v);
		h[u].push_back(a[v]);
		h[v].push_back(a[u]);
	}
	for(int i = 1; i <= n; i++) {
		int m = h[i].size();
		sort(h[i].begin(), h[i].end());
		if(m) {
			ans1 = max(ans1, (a[i] + h[i][m - 1]) / 2.0);
			ans2 = min(ans2, (a[i] + h[i][0]) / 2.0);
		}
		if(m > 1) {
			ans1 = max(ans1, (a[i] + h[i][m - 1] + h[i][m - 2]) / 3.0);
			ans2 = min(ans2, (a[i] + h[i][0] + h[i][1]) / 3.0);
		}
	}
	double ans = max(ans1 * ans1, ans2 * ans2);
	printf("%.6lf", ans / 4);
	return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值