CF1656F Parametric MST 题解

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)Eauav+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 ∀1in,如果 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 n1 条边的最小生成树。

现在来考虑一下无解的情况:

  • 如果 ∀ 1 ≤ i ≤ n , a i + t > 0 \forall 1\le i\le n,a_i+t>0 ∀1in,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)Eauav+t(u,v)E(au+av)=a1i=2nai+t[(n1)a1+i=2nai]

    可以发现, W W W 是关于 t t t 的一次函数。由于满足 ∀ 1 ≤ i ≤ n , a i + t > 0 \forall 1\le i\le n,a_i+t>0 ∀1in,ai+t>0,所以如果一次项系数 ( n − 1 ) a 1 + ∑ i = 2 n a i > 0 (n-1)a_1+\sum\limits_{i=2}^na_i>0 (n1)a1+i=2nai>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 ∀1in,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=1n1ai+t[(n1)an+i=1n1ai]

    类似的,如果 ( n − 1 ) a n + ∑ i = 1 n − 1 a i < 0 (n-1)a_n+\sum\limits_{i=1}^{n-1}a_i<0 (n1)an+i=1n1ai<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 (n1)a1+i=2nai>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 (n1)an+i=1n1ai<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 a1tan(否则函数不收敛,然而先前我们已经判断了无解的情况)。

    − t ∈ [ a i , a i + 1 ] ( 1 ≤ i < n ) -t\in[a_i,a_{i+1}](1\le i<n) t[ai,ai+1](1i<n) 时,最优的连边方式之一是将所有的 1 ≤ j ≤ i 1\le j\le i 1ji 向结点 n n n 连边(因为这些 j j j 满足 a j + t ≤ 0 a_j+t\le 0 aj+t0),其他结点向 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=2iaj+t[(i1)an+j=2iaj]+a1j=i+1naj+t[(ni)a1+j=i+1naj]

    (注意到这里 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值