zoukankan      html  css  js  c++  java
  • CF685C Optimal Point

    CF685C

    在一个三维空间中有若干个点。

    你要找到一个整点使得它与若干个整点的曼哈顿距离最大值最小。

    (nle 10^5)

    (坐标le 10^{18})


    简单题+调半天

    首先可以类比二维平面的曼哈顿距离和切比雪夫距离的转化:((x,y))到原点的曼哈顿距离为(|x|+|y|),切比雪夫距离为(max(|x|,|y|))。那么((x,y))到原点的曼哈顿距离相当于((x+y,x-y))到原点的切比雪夫距离。具体的推法考虑(|x|=max(x,-x)),分类讨论将四种情况写出来求最大值,发现可以用切比雪夫距离来表示。

    但放到三维,曼哈顿距离为(|x|+|y|+|z|)。这个东西实际上不能转化成切比雪夫距离。但这个套路还可以利用:根据每一维的正负号分成八类,然后这个点可以从三维空间映射到一个四维空间。

    形象地说,原点一定距离以内的点形成一个八面体。然后每个平面形如(x+y+z=d)(x+y-z=d)这种形式。

    显然这题要二分答案,二分答案之后求这些八面体的交集。

    将它映射到的四维空间求个交集,于是就得到了(x+y+z,x+y-z,x-y+z,x-y-z)的范围。

    然而求出交集还不一定有解。因为这四个维度并不是互不相干的。

    (a=x+y-z,b=x-y+z,c=x-y-z),那么有(x+y+z=a+b-c)(x=frac{a+b}{2},y=frac{a-c}{2},z=frac{b-c}{2})

    问题变成了:找到(a,b,c)满足(aequiv bequiv c pmod 2)(a+b-c,a,b,c)在各自的范围内。

    前面这个同余的性质好做,枚举余数(r),然后将(a)映射到(frac{a-r}{2}),相应的区间也改一下。

    后面的重点是要让(a+b-c)在范围内。先让(a,b,c)取到最小值,如果不满足(a+b-c)的限制,那么把(a)调大,不行就再把(b)调大,还不行就再把(c)调小。由于通过这种方式我们得到的(a+b-c)的值是连续的,所以如果找不到一定无解。

    细节有点多。。。(还有吐槽一下坐标开到(10^{18}),二分范围(6*10^{18}),直接打mid=l+r>>1会挂的。。。解决的话可以开ull或者写mid=l+(r-l>>1)

    以下的代码有非常多得到调试语句,所以显得特别长。。。


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cassert>
    #include <climits>
    #define N 100010
    #define ll long long
    #define ull unsigned long long
    int n;
    struct DOT{long long x[3];} d[N],ans;
    bool in(ll x,ll l,ll r){return l<=x && x<=r;}
    ll m[8],m_[8];
    void calc(ll a,ll b,ll c,ll r){
    	a=2*a+r,b=2*b+r,c=2*c+r;
    	assert(m[0]<=a+b-c && a+b-c<=m[4]);
    	ans.x[0]=a+b>>1;
    	ans.x[1]=a-c>>1;	
    	ans.x[2]=b-c>>1;
    	assert(in(a,m[1],m[5]));
    	assert(in(b,m[2],m[6]));
    	assert(in(c,m[3],m[7]));
    }
    bool judge(ll l){
    	for (int i=0;i<4;++i)
    		m[i]=LLONG_MIN,m[i+4]=LLONG_MAX;
    	for (int i=1;i<=n;++i){
    		for (int j=0;j<4;++j){
    			ll t=d[i].x[0];
    			for (int k=1;k<3;++k)
    				t+=d[i].x[k]*(j>>2-k&1?-1:1);
    			m[j]=max(m[j],t-l);
    			m[j+4]=min(m[j+4],t+l);
    		}
    	}
    	for (int i=0;i<4;++i)
    		if (m[i]>m[i+4])
    			return 0;
    //	for (int i=0;i<4;++i)
    //		cout<<(long double)m[i]<<" "<<(long double)m[i+4]<<endl;
    //		printf("%.0lf %.0lf
    ",(double)m[i],(double)m[i+4]);
    	for (int r=0;r<=1;++r){
    		bool cant=0;
    		for (int i=0;i<4;++i){
    			m_[i]=(m[i]-r)+1>>1;
    			m_[i+4]=(m[i+4]-r)>>1;
    			if (m_[i]>m_[i+4])
    				cant=1;
    		}
    		if (cant) continue;
    //		for (int i=0;i<4;++i)
    //			cout<<(long double)m[i]<<" "<<(long double)m[i+4]<<endl;
    //			printf("%.0lf %.0lf
    ",(double)m_[i],(double)m_[i+4]);
    		ll a=m_[1],b=m_[2],c=m_[7];
    //		printf("%.0lf
    ",(double)a+b-c);
    		if (in(a+b-c,m_[0],m_[4])){
    			calc(a,b,c,r);
    			return 1;
    		}
    		ll t=m_[0]-(a+b-c);
    //		printf("%.0lf %.0lf
    ",(double)a+b-c+t,(double)a+t);
    		if (in(a+t,m_[1],m_[5])){
    			calc(a+t,b,c,r);
    			return 1;
    		}
    		else
    			t-=m_[5]-a,a=m_[5];
    //		printf("%.0lf %.0lf
    ",(double)a+b-c+t,(double)b+t);
    		if (in(b+t,m_[2],m_[6])){
    			calc(a,b+t,c,r);
    			return 1;
    		}
    		else
    			t-=m_[6]-b,b=m_[6];
    //		printf("%.0lf %.0lf
    
    ",(double)a+b-c+t,(double)c-t);
    		if (in(c-t,m_[3],m_[7])){
    			calc(a,b,c-t,r);
    			return 1;
    		}
    //		a=m_[5],b=m_[6],c=m_[3];
    //		if (in(a+b-c,m_[0],m_[4])){
    //			calc(a,b,c,r);
    //			return 1;
    //		}
    //		t=(a+b-c)-m_[4];
    //		if (in(a-t,m_[1],m_[5])){
    //			calc(a-t,b,c,r);
    //			return 1;
    //		}
    //		if (in(b-t,m_[2],m_[6])){
    //			calc(a,b-t,c,r);
    //			return 1;
    //		}
    //		if (in(c+t,m_[3],m_[7])){
    //			calc(a,b,c+t,r);
    //			return 1;
    //		}
    	}
    	return 0;
    }
    int main(){
    	freopen("in.txt","r",stdin);
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%d",&n);
    		for (int i=1;i<=n;++i)
    			scanf("%lld%lld%lld",&d[i].x[0],&d[i].x[1],&d[i].x[2]);
    //		printf("%.0lf
    ",(double)tmp);
    		ll l=0,r=6000000000000000000,res=-1;
    //		printf("%d
    ",judge(r));
    		while (l<=r){
    			ll mid=(ull)l+(ull)r>>1;
    			if (judge(mid))
    				r=(res=mid)-1;
    			else
    				l=mid+1;
    		}
    //		printf("%lld
    ",(long long)res);
    		judge(res);
    		ll tmp=0;
    		for (int i=1;i<=n;++i)
    			tmp=max(tmp,abs(ans.x[0]-d[i].x[0])+abs(ans.x[1]-d[i].x[1])+abs(ans.x[2]-d[i].x[2]));
    //		printf("%lld
    ",tmp);
    		printf("%lld %lld %lld
    ",ans.x[0],ans.x[1],ans.x[2]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    jquery ajax全解析
    java 远程调试 remote java application
    w3c html dom
    ngx_php
    websocket+前后端分离+https的nginx配置
    CentOS6下基于Nginx搭建mp4/flv流媒体服务器
    nginx could not build the server_names_hash 解决方法
    Nginx 实现AJAX跨域请求
    Nginx与Apache的Rewrite规则的区别
    nginx支持pathinfo模式
  • 原文地址:https://www.cnblogs.com/jz-597/p/13732920.html
Copyright © 2011-2022 走看看