【CF1656F】Parametric MST(贪心)
- 给定一个长度为 \(n\) 的序列 \(a_{1\sim n}\)。
- 定义图 \(K_n(t)\) 为一张完全图,满足点 \(i,j\) 之间的边权是 \(a_ia_j+t(a_i+a_j)\)。
- 设 \(f(t)\) 为 \(K_n(t)\) 最小生成树的权值,对所有 \(t\) 求出 \(f(t)\) 的最大值,或判断为
INF
。 - \(2\le n\le2\times10^5\),\(-10^6\le a_i\le10^6\)
贪心
确定 \(i\) 时,\(a_ia_j+t(a_i+a_j)=(t+a_i)a_j+ta_i\)。
因为 \(ta_i\) 是个定值,所以只需考虑 \(t+a_i\) 的正负,若 \(t+a_i\) 为正则肯定贪心选择最小的 \(a_j\),否则选择最大的 \(a_j\)。
先把 \(t\) 分别取到 \(+\infty\) 和 \(-\infty\),此时只需将 \(a_i\) 排序,所有点都与第 \(1/n\) 个点配对,检验一下答案能否取 INF
。
否则,枚举 \(t\) 在 \([-a_{i+1},-a_i]\) 之间,前 \(i\) 个点会贪心选择第 \(n\) 个点,之后的点会贪心选择第 \(1\) 个点。
发现贪心选一定可以连通,而且一定是第 \(1\) 个点和第 \(n\) 个点之间互相配对,只要少计算一次它们的贡献就得到了最小生成树。
所以可以把这个范围内的 \(f(t)\) 表示成一个关于 \(t\) 的一次函数,最大值肯定取在端点处。
代码:\(O(n\log n)\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Rg register
#define RI Rg int
#define Cn const
#define CI Cn int&
#define I inline
#define W while
#define N 200000
#define LL long long
using namespace std;
namespace FastIO
{
#define FS 100000
#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
#define D isdigit(oc=tc())
int ff;char oc,FI[FS],*FA=FI,*FB=FI;
Tp I void read(Ty& x) {x=0,ff=1;W(!D) ff=oc^'-'?1:-1;W(x=(x<<3)+(x<<1)+(oc&15),D);x*=ff;}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}using namespace FastIO;
int n,a[N+5];
int main()
{
RI Tt,i;LL t,A,B,ans;read(Tt);W(Tt--)
{
for(read(n),i=1;i<=n;++i) read(a[i]);sort(a+1,a+n+1);
for(t=0,i=2;i<=n;++i) t+=a[1]+a[i];if(t>0) {puts("INF");continue;}//t取INF
for(t=0,i=1;i<n;++i) t+=a[i]+a[n];if(t<0) {puts("INF");continue;}//t取-INF
for(A=B=0,i=1;i^n;++i) A+=1LL*a[1]*a[i],B+=a[1]+a[i];//所有点都贪心选择1
for(ans=-1e18,i=1;i^n;++i) A+=1LL*(a[n]-a[1])*a[i],B+=a[n]-a[1],ans=max(ans,max(A-1LL*B*a[i],A-1LL*B*a[i+1]));//i改成选择n,最大值一定取在端点处
printf("%lld\n",ans);
}return 0;
}
待到再迷茫时回头望,所有脚印会发出光芒