题意:给定t组数据,每组给n个点(x,y,z)。求一个点(X,Y,Z)使得max(|xi-X|+|yi-Y|+|zi-Z|)最小。
题解:
首先二分答案 δ
。假设最优的点是 (X,Y,Z)
,
那么对于任意的点 i
有∣xi−X∣+∣yi−Y∣+∣zi−Z∣≤δ
因为
∣xi−X∣=max{xi−X,X−xi},
∣yi−Y∣=max{yi−Y,Y−yi},
∣zi−Z∣=max{zi−Z,Z−zi}.
所以
∣xi−X∣+∣yi−Y∣+∣zi−Z∣=max{(xi+yi+zi)−(X+Y+Z),…}≤δ.
总之,
max{xi+yi+zi}−δ≤X+Y+Z≤min{xi+yi+zi}+δ,
max{−xi+yi+zi}−δ≤−X+Y+Z≤min{−xi+yi+zi}+δ,
max{xi+yi−zi}−δ≤X+Y−Z≤min{xi+yi−zi}+δ,
max{−xi+yi−zi}−δ≤−X+Y−Z≤min{−xi+yi−zi}+δ.
为了解不等式组,令 S=Y+Z
,我们知道
max{xi+yi+zi}−δ−X≤S≤min{xi+yi+zi}+δ−X,
max{−xi+yi+zi}−δ+X≤S≤min{−xi+yi+zi}+δ+X.
即区间
[max{xi+yi+zi}−δ−X,min{xi+yi+zi}+δ−X]
和区间
[max{−xi+yi+zi}−δ+X,min{−xi+yi+zi}+δ+X]
有交,解出 X
的范围。
同理,令 D=Y−Z
,也可以解出 X
的范围。如果 X
的解集不空,任意选一个 X=X0
,得到 S
和 D
的范围。
如果范围内存在一组 (S,D)
同奇偶,那么 (Y,Z)
也有解。
如果奇偶性出现问题,需要再取一组 X=X1
.
具体实现时,中间运算的结果可能会超过 64 位整数。 我的代码小心地避免了溢出。
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int MAX=1000000100;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=998244353;
const int INF=1000000010;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
ll mx[5],mi[5];
ll X[5][2],f[7],MX=1e18;
ll get(ll x,ll y) {//防爆longlong
if ((x<0&&y<0)||(x>0&&y>0)) {
ll bo=0;
if (x%2&&y%2) bo=1;
if (x<0&&y<0) return x/2+y/2-bo;
else return x/2+y/2+bo;
} else return (x+y)/2;
}
int pd(ll x) {
f[3]=max(X[1][0]-x,X[2][0]+x);f[4]=min(X[1][1]-x,X[2][1]+x);
f[5]=max(X[3][0]-x,X[4][0]+x);f[6]=min(X[3][1]-x,X[4][1]+x);
if (f[3]>f[4]||f[5]>f[6]) return 0;
if (f[4]>f[3]||f[6]>f[5]) return 1;
if ((f[3]%2+2)%2==(f[5]%2+2)%2) return 1;
return 0;
}
int check(ll x) {
int i;
for (i=1;i<5;i++) {
X[i][0]=mx[i]-x;X[i][1]=mi[i]+x;
if (X[i][0]>X[i][1]) return 0;
}
f[1]=get(X[1][0],-X[2][1]);f[2]=get(X[1][1],-X[2][0]);//[x1,x2]
f[3]=get(X[3][0],-X[4][1]);f[4]=get(X[3][1],-X[4][0]);//[x3,x4]
f[1]=max(f[1],max(f[3],-MX));f[2]=min(f[2],min(f[4],MX));//[x1,x2]&[x3,x4],防爆longlong
if (f[1]>f[2]) return 0;
for (ll j=f[1];j<=f[2];j++)
if (pd(j)) return 1;
return 0;
}
int main()
{
int i,n,t;
ll x,y,z,mxx=3*1e18;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (i=1;i<5;i++) {
mi[i]=mxx;mx[i]=-mxx;
}
for (i=1;i<=n;i++) {
scanf("%I64d%I64d%I64d", &x, &y, &z);
mi[1]=min(mi[1],x+y+z);mx[1]=max(mx[1],x+y+z);
mi[2]=min(mi[2],-x+y+z);mx[2]=max(mx[2],-x+y+z);
mi[3]=min(mi[3],x+y-z);mx[3]=max(mx[3],x+y-z);
mi[4]=min(mi[4],-x+y-z);mx[4]=max(mx[4],-x+y-z);
}
ll l=-1,r=mxx,mid=(l+r)>>1;
while (l+1<r)
if (check(mid)) { r=mid;mid=(l+r)>>1; }
else { l=mid;mid=(l+r)>>1; }
check(r);
for (ll j=f[1];j<=f[2];j++)
if (pd(j)) {
x=j;
if (f[3]==f[4]||f[5]==f[6]) {
if (f[3]==f[4]) {
y=f[3];
if ((f[5]%2+2)%2==(f[3]%2+2)%2) z=f[5];
else z=f[5]+1;
} else {
z=f[5];
if ((f[5]%2+2)%2==(f[3]%2+2)%2) y=f[3];
else y=f[3]+1;
}
} else {
y=f[3];
if ((f[5]%2+2)%2==(f[3]%2+2)%2) z=f[5];
else z=f[5]+1;
}
break ;
}
printf("%I64d %I64d %I64d\n", x, get(y,z), get(y,-z));
}
return 0;
}
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int MAX=1000000100;
const int mod=100000000;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=998244353;
const int INF=1000000010;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
ll mx[5],mi[5];
ll X[5][2],f[7],MX=1e18;
ll get(ll x,ll y) {//防爆longlong
if ((x<0&&y<0)||(x>0&&y>0)) {
ll bo=0;
if (x%2&&y%2) bo=1;
if (x<0&&y<0) return x/2+y/2-bo;
else return x/2+y/2+bo;
} else return (x+y)/2;
}
int pd(ll x) {
f[3]=max(X[1][0]-x,X[2][0]+x);f[4]=min(X[1][1]-x,X[2][1]+x);
f[5]=max(X[3][0]-x,X[4][0]+x);f[6]=min(X[3][1]-x,X[4][1]+x);
if (f[3]>f[4]||f[5]>f[6]) return 0;
if (f[4]>f[3]||f[6]>f[5]) return 1;
if ((f[3]%2+2)%2==(f[5]%2+2)%2) return 1;
return 0;
}
int check(ll x) {
int i;
for (i=1;i<5;i++) {
X[i][0]=mx[i]-x;X[i][1]=mi[i]+x;
if (X[i][0]>X[i][1]) return 0;
}
f[1]=get(X[1][0],-X[2][1]);f[2]=get(X[1][1],-X[2][0]);//[x1,x2]
f[3]=get(X[3][0],-X[4][1]);f[4]=get(X[3][1],-X[4][0]);//[x3,x4]
f[1]=max(f[1],max(f[3],-MX));f[2]=min(f[2],min(f[4],MX));//[x1,x2]&[x3,x4],防爆longlong
if (f[1]>f[2]) return 0;
for (ll j=f[1];j<=f[2];j++)
if (pd(j)) return 1;
return 0;
}
int main()
{
int i,n,t;
ll x,y,z,mxx=3*1e18;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (i=1;i<5;i++) {
mi[i]=mxx;mx[i]=-mxx;
}
for (i=1;i<=n;i++) {
scanf("%I64d%I64d%I64d", &x, &y, &z);
mi[1]=min(mi[1],x+y+z);mx[1]=max(mx[1],x+y+z);
mi[2]=min(mi[2],-x+y+z);mx[2]=max(mx[2],-x+y+z);
mi[3]=min(mi[3],x+y-z);mx[3]=max(mx[3],x+y-z);
mi[4]=min(mi[4],-x+y-z);mx[4]=max(mx[4],-x+y-z);
}
ll l=-1,r=mxx,mid=(l+r)>>1;
while (l+1<r)
if (check(mid)) { r=mid;mid=(l+r)>>1; }
else { l=mid;mid=(l+r)>>1; }
check(r);
for (ll j=f[1];j<=f[2];j++)
if (pd(j)) {
x=j;
if (f[3]==f[4]||f[5]==f[6]) {
if (f[3]==f[4]) {
y=f[3];
if ((f[5]%2+2)%2==(f[3]%2+2)%2) z=f[5];
else z=f[5]+1;
} else {
z=f[5];
if ((f[5]%2+2)%2==(f[3]%2+2)%2) y=f[3];
else y=f[3]+1;
}
} else {
y=f[3];
if ((f[5]%2+2)%2==(f[3]%2+2)%2) z=f[5];
else z=f[5]+1;
}
break ;
}
printf("%I64d %I64d %I64d\n", x, get(y,z), get(y,-z));
}
return 0;
}