为了能到远方,脚下的每一步都不能少|

Aurora-JC

园龄:3年1个月粉丝:3关注:4

📂题解
🔖贪心
2022-11-08 22:03阅读: 47评论: 0推荐: 1

CF1656F Parametric MST

给定一张 n 个点的无向完全图 Kn(t),点 i 和点 j 之间的边的边权 wi,j(t)ai×aj+t×(ai+aj),其中 t 为任意实数。

定义 f(t)Kn(t) 的最小生成树的边权和。输出 f(t) 的最大值,无最大值则输出 INF

分析

首先将 a 从小到大排序,设 sa 的前缀和
,确定 i 时,aiaj+t(ai+aj)=(t+ai)aj+tai

因为 tai 是个定值,所以只需考虑 t+ai 的正负,若 t+ai 为正则肯定贪心选择最小的 aj,否则选择最大的 aj 。所以,对于 t 非常大,若 (a1(n1)+sns1)>0 则为 INF,同理若 t 是非常小的负数,若 (an(n1)+sns1)<0 则为 INF

其它情况我们观察一下式子 wi,j(t)=aiaj+t(ai+aj)=(ai+t)(aj+t)t2,令bi=ai+t,则权值为 wi,j(t)=bibjt2,令 wi,j=bibjf(t)=mst(n1)t2mst 为最小生成树权值和),对于所有的对于任意一个 t,一定满足 [1,i] bi<0[i+1,n] bi>0,对于 bi<0 我们将其和 max(bi)) 相连,对于 bi>0 我们将其和 min(bi) 相连,这样求出来的就是最小值,通过枚举 t 求解即可。

发现 t 在 [ai+1,ai] 可以把这个范围内的 f(t) 表示成一个关于 t 的一次函数。这怎么理解呢?比如说,t 在 [ai+1,ai] 范围内,每次 +1,最小生成树选择的边是不会变的,则答案就会变化 ai+aj2×t×(n1),( (i,j) 为选择的边),显然 ai+aj 的值不会变,所以为一次函数。所以,最大值肯定取在端点处,所以依次只要枚举 t=ai 的权值,再取个最大值就行了。

code

#include<bits/stdc++.h>
#define N 200005
#define int long long
using namespace std;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
int T,n;
int a[N],s[N];
signed main(){
T=read();
while(T--){
n=read();
for(int i=1;i<=n;++i) a[i]=read();
sort(a+1,a+1+n);
for(int i=1;i<=n;++i) s[i]=s[i-1]+a[i];
if(s[n]-s[1]+a[1]*(n-1)>0||s[n-1]+a[n]*(n-1)<0){printf("INF\n");continue;}
int ans=-1e18;
for(int i=1;i<=n;++i){
int t=-a[i];
int maxn=a[n]+t,minn=a[1]+t;
int ls=s[i]+i*t,rs=s[n]-s[i]+(n-i)*t;
ans=max(ans,ls*maxn+rs*minn-minn*maxn-(n-1)*t*t);
}
printf("%lld\n",ans);
}
return 0;
}

本文作者:Aurora-JC

本文链接:https://www.cnblogs.com/jiangchen4122/p/16871411.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Aurora-JC  阅读(47)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起