@xiaoziyao
2021-07-09T11:59:43.000000Z
字数 2881
阅读 1455
解题报告
CF685C Optimal Point解题报告:
给定 个立体三维坐标系的整点(坐标范围 ),求一个点使得其与所有点的曼哈顿距离最大值最小。( )
优美的胖题。
首先求最大值最小就可以知道要二分这个距离最大值。
考虑怎么 check 这个距离 ,发现这等价于解这个方程组的解(其中 为未知数):
发现这个绝对值很难拆,但由于 ,所以每个不等式可以等价为:
然后不难发现这个不等式可以化作:
设 为前四个式子的最大值, 为后四个式子的最小值,, ,那么等价于:
由于 ,且它们都是整数,所以还有 。
此时套路地枚举 的最后一个二进制位 再处理一下边界,那么模 相同的限制就没了,最后不难用调整法算出一个答案。
时间复杂度: 。
#include<stdio.h>#include<iostream>#define inf 6000000000000000000using namespace std;const int maxn=100005;int T,n;long long ansx,ansy,ansz;long long x[maxn],y[maxn],z[maxn];inline long long ceil(long long x){return x>=0? (x+1)/2ll:-((-x)/2ll);}inline long long floor(long long x){return x>=0? x/2ll:-((-x+1)/2ll);}int check(long long mid){long long al=-inf,bl=-inf,cl=-inf,dl=-inf,ar=inf,br=inf,cr=inf,dr=inf;//al<=a+b+c<=ar,bl<=a<=br,cl<=b<=cr,dl<=c<=drfor(int i=1;i<=n;i++){al=max(al,x[i]+y[i]+z[i]-mid),ar=min(ar,x[i]+y[i]+z[i]+mid);bl=max(bl,-x[i]+y[i]+z[i]-mid),br=min(br,-x[i]+y[i]+z[i]+mid);cl=max(cl,x[i]-y[i]+z[i]-mid),cr=min(cr,x[i]-y[i]+z[i]+mid);dl=max(dl,x[i]+y[i]-z[i]-mid),dr=min(dr,x[i]+y[i]-z[i]+mid);}for(int t=0;t<=1;t++){long long wl=ceil(al-3*t),wr=floor(ar-3*t);long long xl=ceil(bl-t),xr=floor(br-t);long long yl=ceil(cl-t),yr=floor(cr-t);long long zl=ceil(dl-t),zr=floor(dr-t);if(wl<=wr&&xl<=xr&&yl<=yr&&zl<=zr&&xl+yl+zl<=wr&&xr+yr+zr>=wl){long long x=xl,y=yl,z=zl,up=max(0ll,wl-xl-yl-zl);x+=min(up,xr-xl),up-=min(up,xr-xl);y+=min(up,yr-yl),up-=min(up,yr-yl);z+=min(up,zr-zl),up-=min(up,zr-zl);x=((x<<1)|t),y=((y<<1)|t),z=((z<<1)|t);ansx=(y+z)>>1,ansy=(x+z)>>1,ansz=(x+y)>>1;return 1;}}return 0;}int main(){scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&x[i],&y[i],&z[i]);long long L=-1,R=inf+1;while(L+1<R){long long mid=L+(R-L)/2ll;if(check(mid))R=mid;else L=mid;}check(R);printf("%lld %lld %lld\n",ansx,ansy,ansz);}return 0;}
