题目
在一个三维空间中有若干个点。
你要找到一个整点使得它与若干个整点的曼哈顿距离最大值最小。
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+z−xi−yi−zi⩾Ansx+y−z−xi−yi+zi⩾Ansx−y+z−xi+yi−zi⩾Ansx−y−z−xi+yi+zi⩾Ans−x+y+z+xi−yi−zi⩾Ans−x+y−z+xi−yi+zi⩾Ans−x−y+z+xi+yi−zi⩾Ans−x−y−z+xi+yi+zi⩾Ans
移项后的到这样的形式:
{
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+y−z∈[l1,r1]x−y+z∈[l2,r2]x−y−z∈[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+y−z,b=x−y+z,c=x−y−z , 则
a
+
b
−
c
=
x
+
y
+
z
a+b-c=x+y+z
a+b−c=x+y+z , 这里隐含了
a
≡
b
≡
c
(
m
o
d
2
)
a\equiv b\equiv c\pmod 2
a≡b≡c(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);
}
}