Source:CodeTON Round #1 F
为了便于解题,先对 a a a 数组从小到大进行排序。
首先,根据定义可以得出总价值的表达式:
W = ∑ ( u , v ) ∈ E [ a u a v + t ( a u + a v ) ] = ∑ ( u , v ) ∈ E a u a v + t ∑ ( u , v ) ∈ E ( a u + a v ) \begin{aligned} W&=\sum\limits_{(u,v)\in E}[a_ua_v+t(a_u+a_v)]\\ &=\sum\limits_{(u,v)\in E}a_ua_v+t\sum\limits_{(u,v)\in E}(a_u+a_v) \end{aligned} W=(u,v)∈E∑[auav+t(au+av)]=(u,v)∈E∑auav+t(u,v)∈E∑(au+av)
接着,我们需要发现一个比较重要的性质:
- w i , j ( t ) = a i a j + t ( a i + a j ) = ( a i + t ) ( a j + t ) − t 2 w_{i,j}(t)=a_ia_j+t(a_i+a_j)=(a_i+t)(a_j+t)-t^2 wi,j(t)=aiaj+t(ai+aj)=(ai+t)(aj+t)−t2
也就是说,如果固定一个 t t t,那么 t 2 t^2 t2 就是定值,可以暂不考虑; ∀ 1 ≤ i ≤ n \forall 1\le i\le n ∀1≤i≤n,如果 a i + t a_i+t ai+t 是正数,就向结点 1 1 1 连边以最小化该点的贡献;如果 a i + t a_i+t ai+t 是负数,就向结点 n n n 连边(如果 a i + t = 0 a_i+t=0 ai+t=0 那么向哪个点连边都一样)。最后去掉 1 1 1 与 n n n 之间的重边,即可构造出正好有 n − 1 n-1 n−1 条边的最小生成树。
现在来考虑一下无解的情况:
-
如果 ∀ 1 ≤ i ≤ n , a i + t > 0 \forall 1\le i\le n,a_i+t>0 ∀1≤i≤n,ai+t>0,那么除了 1 1 1 以外的所有结点向 1 1 1 连边,有
W = ∑ ( u , v ) ∈ E a u a v + t ∑ ( u , v ) ∈ E ( a u + a v ) = a 1 ∑ i = 2 n a i + t [ ( n − 1 ) a 1 + ∑ i = 2 n a i ] \begin{aligned} W&=\sum\limits_{(u,v)\in E}a_ua_v+t\sum\limits_{(u,v)\in E}(a_u+a_v)\\ &=a_1\sum\limits_{i=2}^na_i+t\left[(n-1)a_1+\sum\limits_{i=2}^na_i\right]\\ \end{aligned} W=(u,v)∈E∑auav+t(u,v)∈E∑(au+av)=a1i=2∑nai+t[(n−1)a1+i=2∑nai]
可以发现, W W W 是关于 t t t 的一次函数。由于满足 ∀ 1 ≤ i ≤ n , a i + t > 0 \forall 1\le i\le n,a_i+t>0 ∀1≤i≤n,ai+t>0,所以如果一次项系数 ( n − 1 ) a 1 + ∑ i = 2 n a i > 0 (n-1)a_1+\sum\limits_{i=2}^na_i>0 (n−1)a1+i=2∑nai>0,那么当 t → + ∞ t\rightarrow+\infty t→+∞ 时 W → + ∞ W\rightarrow+\infty W→+∞,该函数不存在最大值。
-
如果 ∀ 1 ≤ i ≤ n , a i + t < 0 \forall 1\le i\le n,a_i+t<0 ∀1≤i≤n,ai+t<0,同理有:
W = a n ∑ i = 1 n − 1 a i + t [ ( n − 1 ) a n + ∑ i = 1 n − 1 a i ] \begin{aligned} W&=a_n\sum\limits_{i=1}^{n-1}a_i+t\left[(n-1)a_n+\sum\limits_{i=1}^{n-1}a_i\right]\\ \end{aligned} W=ani=1∑n−1ai+t[(n−1)an+i=1∑n−1ai]
类似的,如果 ( n − 1 ) a n + ∑ i = 1 n − 1 a i < 0 (n-1)a_n+\sum\limits_{i=1}^{n-1}a_i<0 (n−1)an+i=1∑n−1ai<0,当 t → − ∞ t\rightarrow-\infty t→−∞ 时, W → + ∞ W\rightarrow+\infty W→+∞,不存在最大值。
综上,如果
(
n
−
1
)
a
1
+
∑
i
=
2
n
a
i
>
0
(n-1)a_1+\sum\limits_{i=2}^na_i>0
(n−1)a1+i=2∑nai>0 或
(
n
−
1
)
a
n
+
∑
i
=
1
n
−
1
a
i
<
0
(n-1)a_n+\sum\limits_{i=1}^{n-1}a_i<0
(n−1)an+i=1∑n−1ai<0,边权和不存在最大值,直接输出 INF
即可。
现在来考虑有解时如何寻找解。这时我们就需要引入一个新的性质:
-
如果 W W W 能取到最大值, − t -t −t 的值一定是 a a a 数组中的其中一个元素的值。
证明:
因为一定有解,所以当 W W W 取到极值时, a 1 ≤ − t ≤ a n a_1\le -t\le a_n a1≤−t≤an(否则函数不收敛,然而先前我们已经判断了无解的情况)。
当 − t ∈ [ a i , a i + 1 ] ( 1 ≤ i < n ) -t\in[a_i,a_{i+1}](1\le i<n) −t∈[ai,ai+1](1≤i<n) 时,最优的连边方式之一是将所有的 1 ≤ j ≤ i 1\le j\le i 1≤j≤i 向结点 n n n 连边(因为这些 j j j 满足 a j + t ≤ 0 a_j+t\le 0 aj+t≤0),其他结点向 1 1 1 连边。所以我们可以得到 W W W 的表达式:
W = a n ∑ j = 2 i a j + t [ ( i − 1 ) a n + ∑ j = 2 i a j ] + a 1 ∑ j = i + 1 n a j + t [ ( n − i ) a 1 + ∑ j = i + 1 n a j ] \begin{aligned} W&=a_n\sum\limits_{j=2}^ia_j+t\left[(i-1)a_n+\sum\limits_{j=2}^ia_j\right]+a_1\sum\limits_{j=i+1}^na_j+t\left[(n-i)a_1+\sum_{j=i+1}^na_j\right] \end{aligned} W=anj=2∑iaj+t[(i−1)an+j=2∑iaj]+a1j=i+1∑naj+t[(n−i)a1+j=i+1∑naj]
(注意到这里 1 1 1 和 n n n 之间的边仅仅被连了一次,所以最终不用考虑重边的影响。)
在这里因为 i i i 确定,所以 W W W 还是关于 t t t 的一次函数,极值必然在 − t = a i -t=a_i −t=ai 或 − t = a i + 1 -t=a_{i+1} −t=ai+1 时取到。命题得证。
接下来只用枚举 i = 1 , 2 , … , n i=1,2,\ldots,n i=1,2,…,n,然后令 t = − a i t=-a_i t=−ai,将 t t t 带入证明中的那个表达式算出 W W W 的值。在所有的 W W W 中找到 W max W_{\max} Wmax 并输出即可。
中间那一些求和的式子可以使用前缀和维护。
放代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
main(){
ios::sync_with_stdio(false);
int t; cin>>t;
while(t--){
int n,c=LLONG_MIN; cin>>n;
vector<int> a(n),s;
for(auto &i:a)cin>>i;
sort(a.begin(),a.end()); // 排序
partial_sum(a.begin(),a.end(),back_inserter(s)); // 做前缀和
if(a[0]*(n-2)+s[n-1]>0||a[n-1]*(n-2)+s[n-1]<0)cout<<"INF\n"; // 无解情况
else{
for(int i=0;i<n;i++)
c=max(c,a[0]*(s[n-1]-s[i])-a[i]*(a[0]*(n-i-1)+s[n-1]-s[i])+a[n-1]*(s[i]-s[0])-a[i]*(a[n-1]*i+s[i]-s[0]));
// 带入表达式计算
cout<<c<<endl;
}
}
return 0;
}