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|} ∣V∣∑u∈V(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
∣V∣∑u∈V(−x2+bux)=∣V∣−∣V∣x2+(∑u∈Vbu)x=−x2+∣V∣∑u∈Vbux
其中
∑
u
∈
V
b
u
∣
V
∣
\frac{\sum_{u\in V}b_u}{|V|}
∣V∣∑u∈Vbu为该简单路径上所有节点权值的平均值,令其等于
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=−(x−2avg)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+c,3b+c+d,2a+b,2b+c,2c+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+2b,2a+2d>2b+2c,2a+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+2b与2a+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;
}