【二分答案】【CF685C】Optimal Point

题目

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

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

n<=1e5

思路

容易想到二分答案, 考虑如何判断一个二分的值 A n s Ans Ans 的可行性.
列出不等式组:
{ x + y + z − x i − y i − z i ⩾ A n s x + y − z − x i − y i + z i ⩾ A n s x − y + z − x i + y i − z i ⩾ A n s x − y − z − x i + y i + z i ⩾ A n s − x + y + z + x i − y i − z i ⩾ A n s − x + y − z + x i − y i + z i ⩾ A n s − x − y + z + x i + y i − z i ⩾ A n s − x − y − z + x i + y i + z i ⩾ A n s \left\{\begin{aligned} x+y+z-x_i-y_i-z_i\geqslant Ans\\ x+y-z-x_i-y_i+z_i\geqslant Ans\\ x-y+z-x_i+y_i-z_i\geqslant Ans\\ x-y-z-x_i+y_i+z_i\geqslant Ans\\ -x+y+z+x_i-y_i-z_i\geqslant Ans\\ -x+y-z+x_i-y_i+z_i\geqslant Ans\\ -x-y+z+x_i+y_i-z_i\geqslant Ans\\ -x-y-z+x_i+y_i+z_i\geqslant Ans\\ \end{aligned}\right. x+y+zxiyiziAnsx+yzxiyi+ziAnsxy+zxi+yiziAnsxyzxi+yi+ziAnsx+y+z+xiyiziAnsx+yz+xiyi+ziAnsxy+z+xi+yiziAnsxyz+xi+yi+ziAns
移项后的到这样的形式:
{ x + y + z ∈ [ l 0 , r 0 ] x + y − z ∈ [ l 1 , r 1 ] x − y + z ∈ [ l 2 , r 2 ] x − y − z ∈ [ l 3 , r 3 ] \left\{\begin{aligned} x+y+z\in [l_0,r_0]\\ x+y-z\in [l_1,r_1]\\ x-y+z\in [l_2,r_2]\\ x-y-z\in [l_3,r_3]\\ \end{aligned}\right. x+y+z[l0,r0]x+yz[l1,r1]xy+z[l2,r2]xyz[l3,r3]
a = x + y − z , b = x − y + z , c = x − y − z a=x+y-z, b=x-y+z,c=x-y-z a=x+yz,b=xy+z,c=xyz , 则 a + b − c = x + y + z a+b-c=x+y+z a+bc=x+y+z , 这里隐含了 a ≡ b ≡ c ( m o d 2 ) a\equiv b\equiv c\pmod 2 abc(mod2) , 于是我们枚举 a   m o d   2 a\bmod 2 amod2 , 那么不等式组可以转化成关于 a , b , c a,b,c a,b,c 的不等式组, 这个不等式组很好解.
时间复杂度 O ( n log ⁡ x ) \mathcal O(n\log x) O(nlogx).
实际实现中将 c c c 设为 − x + y + z -x+y+z x+y+z .

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+77;
int T,n;
ll x[N],y[N],z[N],l[4],r[4],L[4],R[4];
void chmax(ll &x,ll y) { x<y?x=y:x; }
void chmin(ll &x,ll y) { x > y?x=y:x; }
bool check(ll p,bool prt)
{
	for(int i=0; i<4; ++i) l[i]=-6e18,r[i]=6e18;
	for(int i=1; i<=n; ++i) {
		chmin(r[0],x[i]+y[i]+z[i]+p);
		chmax(l[0],x[i]+y[i]+z[i]-p);
		chmin(r[1],-x[i]+y[i]+z[i]+p);
		chmax(l[1],-x[i]+y[i]+z[i]-p);
		chmin(r[2],x[i]-y[i]+z[i]+p);
		chmax(l[2],x[i]-y[i]+z[i]-p);
		chmin(r[3],x[i]+y[i]-z[i]+p);
		chmax(l[3],x[i]+y[i]-z[i]-p);
	}

	for(int i=0; i<4; ++i)
		if(l[i] > r[i]) return 0;
	for(int A=0,bz; A<2; ++A) {
		L[0]=l[0]-3 * A,R[0]=r[0]-3 * A;
		for(int i=1; i<4; ++i) L[i]=l[i]-A,R[i]=r[i]-A;
		for(int i=0; i<4; ++i) L[i]=L[i]+1>>1,R[i] >>= 1;

		bz=1;
		for(int i=0; i<4; ++i)
			if(L[i] > R[i]) {
				bz=0;
				break;
			}
		if(!bz) continue;
		ll L0=L[1]+L[2]+L[3],R0=R[1]+R[2]+R[3];
		if(R[0] >= L0 && R0 >= L[0]) {
			if(prt) {
				ll a=L[1],b=L[2],c=L[3];
				if(a+b+c<L[0]) a+=min(R[1]-L[1],L[0]-a-b-c);
				if(a+b+c<L[0]) b+=min(R[2]-L[2],L[0]-a-b-c);
				if(a+b+c<L[0]) c+=min(R[3]-L[3],L[0]-a-b-c);
				printf("%lld %lld %lld\n",b+c+A,a+c+A,a+b+A);
			}
			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]);
		ll l=0,r=6e18,rs=r,mid;
		while(l<=r)
			check(mid=l+r>>1,0)?rs=mid,r=mid-1:l=mid+1;
		check(rs,1);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值