solution:
设mx为最大点的坐标,mi为最小点的坐标的绝对值。
不妨设mi<mx。
则上限为mx。
首先有一个结论:一定有一个点在原点。证明如下:
分类讨论,不妨设左边叫A,右边叫B。
若A<B<0:这种答案就为上限。
若A<0<B:
在这种情况下,A、B绝对值较小的那一边的所有点的距离一定为|x|。因为跨传送门显然不优。
根据假设,我们发现一定是|A|<|B|的。(否则答案仍为上限)
也就是说只有右边的点会用到传送门,如果要用传送门的话,付出的代价为|A|+点到B的距离。
|A|显然为0是最优的。
若0<A<B:这种情况和上种证明类似,可知|A|一定不会>0。
那么问题变成了:数轴上有点集S,你需要选择一个点作为关键点P,dis定义为min(x to 0 , x to P),使得maxdis最小。
按照坐标排序后,显然,一定是前面一部分直接去0,后面的所有点去P。
枚举i,表示i前面的点去0,i+1-n去P。则此时贡献为max(x[i],(x[n]-x[i+1]+1)/2)。取个最小值即可。
注意别忘了还要和mi取max。
复杂度O(nlogn),瓶颈在排序。
代码如下:
#include<bits/stdc++.h> using namespace std; inline int read() { int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } #define mid ((l+r)>>1) #define mp make_pair #define pb push_back #define fi first #define se second #define REP(x) for(int i=head[x],y=a[i].to;i;i=a[i].next,y=a[i].to) if(y!=fa) #define FOR(i,a,b) for(int i=a;i<=b;i++) typedef long long ll; typedef long double ld; const int N=1010100; int x[N],n,mx,mi,ans,sta[N],top; const int INF=1e9+10; int main() { int T=read(); while(T--) { n=read(); mx=mi=ans=top=0; for(int i=1;i<=n;i++) { x[i]=read(); if(x[i]>=0)mx=max(mx,abs(x[i])); else mi=max(mi,abs(x[i])); } if(mi>mx) { for(int i=1;i<=n;i++) x[i]=-x[i]; swap(mx,mi); } for(int i=1;i<=n;i++) { if(x[i]<=0) ans=max(ans,abs(x[i])); else sta[++top]=x[i]; } sort(sta+1,sta+top+1); int d=INF; for(int i=0;i<top;i++) { int x=sta[i]; d=min(d,max(x,(sta[top]-sta[i+1]+1)/2)); } ans=max(ans,d); cout<<ans<<'\n'; } }