把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【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;
}
posted @ 2022-04-05 16:31  TheLostWeak  阅读(95)  评论(0编辑  收藏  举报