Codeforces Round #359 (Div. 2)E. Optimal Point

链接:http://codeforces.com/contest/686/problem/E

题意:给定t组数据,每组给n个点(x,y,z)。求一个点(X,Y,Z)使得max(|xi-X|+|yi-Y|+|zi-Z|)最小。

分析:叉姐的题解很清楚了,我就不再重复一遍了。叉姐题解链接。O(t*log(3e18))。

代码:

#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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值